1 %p 3000
2 
3 %{
4 
5 /* $Id: lex.l,v 4.22 2011/01/02 18:31:53 tom Exp $
6  *
7  * Lexical analyzer for C function prototype generator
8  *
9  *	This is designed to parse lexically at the top level (e.g., of extern
10  *	objects such as procedures).  The corresponding yacc-grammar expects
11  *	that curly-braces (for function bodies) are recognized as a single
12  *	token, BRACES.  Similarly, square-brackets and their contents are
13  *	passed back as BRACKETS.
14  *
15  *	Assignments at the top level are data-initialization statements.
16  *	These are returned as INITIALIZER.
17  *
18  *	The logic here recognizes tokens inside curly-braces, but does not
19  *	pass them back to the grammar.
20  *
21  * Apollo extensions:
22  *	"&" is ignored when creating lint-libraries, because we ignore
23  *	expressions of all kinds.  Note that function-prototypes may use "&" to
24  *	denote reference-parameters.  By ignoring that as well, we make the
25  *	output compatible with lint (kludge).
26  *
27  *	Similarly, ignore "std_$call", since it is not compatible with lint.
28  *
29  *	CPP_INLINE handles a special case of the Apollo CC 6.7 compiler that
30  *	uses inline attribute declarations, e.g.
31  *
32  *		int	foo #attribute[aligned(1)];
33  *
34  *	In CC 6.8 this behavior is hidden by a macro.
35  *
36  * VAX/VMS extensions:
37  *	Treat the keywords 'globalref', etc., as 'extern'.
38  *
39  *	The keywords 'noshare' and 'readonly' are type-qualifiers.
40  *
41  * GCC extensions:
42  *	The keywords '__attribute__', '__inline', '__inline__', '__signed',
43  *	'__signed__'. and '__extension__'
44  */
45 
46 #define	result(nn)	count(); if (!brackets && unnested()) return(nn)
47 
48 #define	is_IDENTIFIER	    save_text_offset();\
49 			    return type_of_name(yytext);
50 
51 #if !OPT_LINTLIBRARY
52 #define gcc_attribute   absorb_special	/* otherwise, we don't care */
53 #endif
54 
55 #ifdef	apollo
56 #define	apollo_keyword
57 #define	apollo_special	absorb_special()
58 #else
59 #define	apollo_keyword	is_IDENTIFIER
60 #define	apollo_special	is_IDENTIFIER
61 #endif
62 
63 #ifdef	vms
64 #define	vms_extern	save_text_offset(); return(T_EXTERN);
65 #define	vms_keyword	save_text_offset();
66 #else /* unix */
67 #define	vms_extern	is_IDENTIFIER
68 #define	vms_keyword	is_IDENTIFIER
69 #endif /* vms/unix */
70 
71 char *varargs_str;		/* save printflike/scanflike text */
72 int varargs_num;		/* code to save "VARARGS" */
73 int debug_trace;		/* true if we trace token-level stuff */
74 char base_file[BUFSIZ];		/* top-level file name */
75 
76 static int asm_level;		/* parenthesis level for "asm" parsing */
77 static int save_cpp;		/* true if cpp-text within curly braces */
78 static int in_cpp;		/* true while we are within cpp-text */
79 static int curly;		/* number of curly brace nesting levels */
80 static int ly_count;		/* number of occurances of %% */
81 
82 #ifdef FLEX_SCANNER
83 /* flex scanner state */
84 static YY_BUFFER_STATE *buffer_stack;
85 
86 #ifdef __cplusplus
87 #define LexInput() yyinput()
88 #endif
89 
90 #endif /* FLEX_SCANNER */
91 
92 #ifndef LexInput
93 #define LexInput() input()
94 #endif
95 
96 static unsigned inc_limit;	/* stack size */
97 static int inc_depth;		/* include nesting level */
98 static IncludeStack *inc_stack;	/* stack of included files */
99 static SymbolTable *included_files;	/* files already included */
100 
101 static int type_of_name(char *name);
102 static void startCpp(int level);
103 static void finishCpp(void);
104 #if defined(apollo) || !OPT_LINTLIBRARY
105 static void absorb_special(void);
106 #endif
107 #if OPT_LINTLIBRARY
108 static void gcc_attribute(void);
109 #endif
110 static void update_line_num(void);
111 static void save_text(void);
112 static void save_text_offset(void);
113 static void get_quoted(void);
114 static void get_comment(void);
115 static void get_cpp_directive(int copy);
116 static void parsing_file_name(unsigned need);
117 static void do_include(char *f);
118 static void include_file(char *name, int convert);
119 static void put_file(FILE *outf);
120 static void put_quoted(int c);
121 
122 #if OPT_LINTLIBRARY
123 static int decipher_comment(char *keyword, int len);
124 #endif
125 
126 %}
127 
128 WS		[ \t]
129 LETTER		[A-Za-z$_]
130 DIGIT		[0-9]
131 ID		{LETTER}({LETTER}|{DIGIT})*
132 QUOTE		[\"\']
133 
134 %s CPP1 INIT1 INIT2 CURLY LEXYACC ASM CPP_INLINE
135 %%
136 
137 \n			{ save_text(); cur_file->line_num++;
138 			    cur_declarator = NULL; }
139 
140 "/*"			{ save_text(); get_comment(); }
141 "//".*$ 		save_text();
142 
143 <INITIAL>"&"		{ save_text(); return '&'; /* C++ ref-variable? */ }
144 
145 <LEXYACC>^"%%"		{ save_text(); if (++ly_count >= 2) BEGIN INITIAL; }
146 <LEXYACC>^"%{"		{ save_text(); BEGIN INITIAL; }
147 <LEXYACC>{QUOTE}	get_quoted();
148 <LEXYACC>.		save_text();
149 <INITIAL>^"%}"		{ save_text(); BEGIN LEXYACC; }
150 
151 <INITIAL>#{WS}* 	{ save_text(); startCpp(0); }
152 <INITIAL>"??="{WS}* 	{ save_text(); startCpp(0); }
153 
154 <CPP1>attribute		{ BEGIN CPP_INLINE; /* apollo */}
155 <CPP1>options		{ BEGIN CPP_INLINE; /* apollo */}
156 <CPP_INLINE>[^;]*	finishCpp();
157 
158 <CPP1>define{WS}+{ID}	{
159 			    char *name;
160 			    char *value;
161 
162 			    save_text();
163 
164 			    *(name = (char *) xmalloc((size_t) (yyleng + 1))) = '\0';
165 			    sscanf(yytext, "define %s", name);
166 
167 			    get_cpp_directive(1);
168 
169 			    *(value = (char *) xmalloc(1 + strlen(temp_buf))) = '\0';
170 			    sscanf(temp_buf, "%s", value);
171 
172 			    new_symbol(define_names, name, value, DS_NONE);
173 
174 			    free(name);
175 			    free(value);
176 			}
177 
178 <CPP1>include{WS}*	{
179 			    save_text();
180 
181 			    get_cpp_directive(1);
182 
183 			    if (temp_buf[0] != '"' && temp_buf[0] != '<') {
184 				Symbol *sym = find_symbol(define_names, temp_buf);
185 				if (sym != NULL && sym->value != NULL) {
186 				    need_temp(strlen(sym->value));
187 				    strcpy(temp_buf, sym->value);
188 				} else {
189 				    temp_buf[0] = '\0';
190 				}
191 			    }
192 			    if (temp_buf[0] != '\0')
193 				do_include(temp_buf);
194 			}
195 
196 <CPP1>line{WS}+[0-9]+{WS}+\".*$  {
197 			    save_text();
198 
199 			    parsing_file_name((unsigned) yyleng);
200 			    sscanf(yytext, "line %u \"%[^\"]\"",
201 					   &cur_file->line_num,
202 					   cur_file->file_name);
203 
204 			    cur_file->line_num--;
205 			    track_in();
206 			    finishCpp();
207 			}
208 <CPP1>[0-9]+{WS}+\".*$  {
209 			    save_text();
210 
211 			    parsing_file_name((unsigned) yyleng);
212 			    sscanf(yytext, "%u \"%[^\"]\"",
213 					   &cur_file->line_num,
214 					   cur_file->file_name);
215 
216 			    cur_file->line_num--;
217 			    track_in();
218 			    finishCpp();
219 			}
220 <CPP1>[0-9]+.*$ 	{
221 			    save_text();
222 			    sscanf(yytext, "%u ", &cur_file->line_num);
223 			    cur_file->line_num--;
224 			    track_in();
225 			    finishCpp();
226 			}
227 
228 <CPP1>. 		{ save_text(); get_cpp_directive(0); }
229 
230 <INITIAL>"("		{ save_text_offset(); return '('; }
231 <INITIAL>")"		{
232 			    save_text();
233 			    if (cur_file->convert)
234 				cur_file->begin_comment =
235 				 ftell(cur_file->tmp_file);
236 			    return ')';
237 			}
238 <INITIAL>"*"		{ save_text_offset(); return '*'; }
239 <INITIAL>[,;]		{
240 			    save_text();
241 			    if (cur_file->convert)
242 				cur_file->begin_comment =
243 				 ftell(cur_file->tmp_file);
244 			    return yytext[0];
245 			}
246 <INITIAL>"..."		{ save_text(); return T_ELLIPSIS; }
247 <INITIAL>\"		{
248 			    get_quoted();
249 			    return T_STRING_LITERAL;
250 			}
251 
252 <INITIAL>"__asm__"	{ save_text(); BEGIN ASM; return T_ASM; }
253 <INITIAL>asm		{ save_text(); BEGIN ASM; return T_ASM; }
254 <ASM>"("		{ ++asm_level; save_text(); }
255 <ASM>")"		{ --asm_level; save_text(); if (asm_level <= 0) { asm_level = 0; BEGIN INITIAL; return T_ASMARG; } }
256 <ASM>{QUOTE} 		get_quoted();
257 <ASM>. 			save_text();
258 
259 <INITIAL>__?based[^(]*\([^)]*\)	{ save_text_offset(); return T_TYPE_QUALIFIER; }
260 
261 <INITIAL>auto		{ save_text_offset(); return T_AUTO; }
262 <INITIAL>extern 	{ save_text_offset(); return T_EXTERN; }
263 <INITIAL>register	{ save_text_offset(); return T_REGISTER; }
264 <INITIAL>static 	{ save_text_offset(); return T_STATIC; }
265 <INITIAL>typedef	{ save_text_offset(); return T_TYPEDEF; }
266 <INITIAL>inline 	{ save_text_offset(); return T_INLINE; }
267 
268 <INITIAL>_Bool		{ save_text_offset(); return T_Bool; }
269 <INITIAL>_Complex	{ save_text_offset(); return T_Complex; }
270 <INITIAL>_Imaginary	{ save_text_offset(); return T_Imaginary; }
271 
272 <INITIAL>char		{ save_text_offset(); return T_CHAR; }
273 <INITIAL>double 	{ save_text_offset(); return T_DOUBLE; }
274 <INITIAL>float		{ save_text_offset(); return T_FLOAT; }
275 <INITIAL>int		{ save_text_offset(); return T_INT; }
276 <INITIAL>void		{ save_text_offset(); return T_VOID; }
277 <INITIAL>long		{ save_text_offset(); return T_LONG; }
278 <INITIAL>short		{ save_text_offset(); return T_SHORT; }
279 <INITIAL>signed 	{ save_text_offset(); return T_SIGNED; }
280 <INITIAL>unsigned	{ save_text_offset(); return T_UNSIGNED; }
281 
282 <INITIAL>enum		{ save_text_offset(); return T_ENUM; }
283 <INITIAL>struct 	{ save_text_offset(); return T_STRUCT; }
284 <INITIAL>union		{ save_text_offset(); return T_UNION; }
285 <INITIAL>va_dcl		{ save_text_offset(); return T_VA_DCL; }
286 
287 <INITIAL>__signed 	{ save_text_offset(); return T_SIGNED; }
288 <INITIAL>__signed__ 	{ save_text_offset(); return T_SIGNED; }
289 <INITIAL>__inline 	{ save_text_offset(); return T_INLINE; }
290 <INITIAL>__inline__ 	{ save_text_offset(); return T_INLINE; }
291 <INITIAL>__extension__ 	{ save_text_offset(); return T_EXTENSION; }
292 <INITIAL>__attribute__	{ gcc_attribute(); }
293 
294 <INITIAL>globalvalue	{ vms_extern; }
295 <INITIAL>globalref	{ vms_extern; }
296 <INITIAL>globaldef	{ vms_extern; }
297 
298 <INITIAL>"std_$call"	{ apollo_keyword; }
299 <INITIAL>"__attribute"	{ apollo_special; }
300 
301 <INITIAL>{ID}		{ is_IDENTIFIER }
302 
303 <INITIAL>\[[^\]]*\]	{
304 			    /* This can't handle the case where a comment
305 			     * containing a ] appears between the brackets.
306 			     */
307 			    save_text_offset();
308 			    update_line_num();
309 			    return T_BRACKETS;
310 			}
311 <INITIAL>"??("[^?]*"??)"	{
312 			    save_text_offset();
313 			    update_line_num();
314 			    return T_BRACKETS;
315 			}
316 
317 <INITIAL>"="		{ save_text(); BEGIN INIT1; return '='; }
318 <INIT1>"{"		{ save_text(); curly = 1; BEGIN INIT2; }
319 <INIT1>[,;]		{
320 			    unput(yytext[yyleng-1]);
321 			    BEGIN INITIAL;
322 			    return T_INITIALIZER;
323 			}
324 <INIT1>{QUOTE}		get_quoted();
325 <INIT1>.		save_text();
326 
327 <INIT2>"{"		{ save_text(); ++curly; }
328 <INIT2>"}"		{
329 			    save_text();
330 			    if (--curly == 0) {
331 				BEGIN INITIAL;
332 				return T_INITIALIZER;
333 			    }
334 			}
335 <INIT2>{QUOTE}		get_quoted();
336 <INIT2>.		save_text();
337 
338 <INITIAL>"{"		{
339 			    save_text();
340 			    curly = 1;
341 			    return_val =
342 			    returned_at = FALSE;
343 			    BEGIN CURLY;
344 			    return T_LBRACE;
345 			}
346 <CURLY>"{"		{ save_text(); ++curly; }
347 <CURLY>"}"		{
348 			    save_text();
349 			    if (--curly == 0) {
350 				BEGIN INITIAL;
351 				return T_MATCHRBRACE;
352 			    }
353 			}
354 <CURLY>{QUOTE}		get_quoted();
355 <CURLY>"return"		{ save_text(); returned_at = TRUE; }
356 <CURLY>";"		{ save_text(); returned_at = FALSE; }
357 <CURLY>#{WS}* 		{ save_text(); startCpp(1); }
358 <CURLY>"??="{WS}* 	{ save_text(); startCpp(1); }
359 <CURLY>.		{ save_text(); return_val |= returned_at; }
360 
361 [ \r\t\f]+		save_text();
362 .			{
363 			    save_text();
364 			    put_error();
365 			    fprintf(stderr, "bad character '%c'\n", yytext[0]);
366 			}
367 %%
368 
369 static void
370 startCpp(int level)
371 {
372     save_cpp = level;
373     in_cpp = TRUE;
374     BEGIN CPP1;
375 }
376 
377 static void
378 finishCpp(void)
379 {
380     in_cpp = FALSE;
381     if (save_cpp)
382 	BEGIN CURLY;
383     else
384 	BEGIN INITIAL;
385 }
386 
387 /*
388  * Skip over embedded __attribute/__attribute_ syntax.
389  */
390 #if defined(apollo) || !OPT_LINTLIBRARY
391 static void
392 absorb_special(void)
393 {
394     int c;
395     int nest = 0;
396     while ((c = input()) > 0) {
397 	if (c == '(')
398 	    nest++;
399 	else if (c == ')') {
400 	    if (--nest <= 0)
401 		break;
402 	}
403     }
404 }
405 #endif
406 
407 #if OPT_LINTLIBRARY
408 /*
409  * This recognizes some of the special attribute macros defined by gcc:
410  *	noreturn
411  *	format(printf,n,m)
412  *	format(scanf,n,m)
413  * and uses that information to construct equivalent lint-library text.
414  * (It's a distinct piece of code from the 'absorb_special()' function to
415  * avoid spurious matches with non-gcc compilers).
416  */
417 static void
418 gcc_attribute(void)
419 {
420     int c, num1, num2;
421     int nest = 0;
422     unsigned len = 0;
423     char bfr[BUFSIZ];
424 
425     while ((c = LexInput()) > 0) {
426 	if (len < sizeof(bfr) - 1 && !isspace(c))
427 	    bfr[len++] = (char) c;
428 	if (c == '(')
429 	    nest++;
430 	else if (c == ')') {
431 	    if (--nest <= 0)
432 		break;
433 	}
434     }
435     bfr[len] = '\0';
436     if (!strcmp(bfr, "((noreturn))")) {
437 	exitlike_func = TRUE;
438     } else if (sscanf(bfr, "((format(printf,%d,%d)))", &num1, &num2) == 2) {
439 	(void) sprintf(bfr, "PRINTFLIKE%d", varargs_num = num1);
440 	varargs_str = xstrdup(bfr);
441     } else if (sscanf(bfr, "((format(scanf,%d,%d)))", &num1, &num2) == 2) {
442 	(void) sprintf(bfr, "SCANFLIKE%d", varargs_num = num1);
443 	varargs_str = xstrdup(bfr);
444     }
445 }
446 #endif
447 
448 /* Decode the current token according to the type-of-name
449  */
450 static int
451 type_of_name(char *name)
452 {
453     if (find_symbol(type_qualifiers, name) != NULL)
454 	return T_TYPE_QUALIFIER;
455     else if (find_symbol(typedef_names, name) != NULL)
456 	return T_TYPEDEF_NAME;
457     else if (find_symbol(define_names, name) != NULL)
458 	return T_DEFINE_NAME;
459     else
460 	return T_IDENTIFIER;
461 }
462 
463 boolean
464 is_typedef_name(char *name)
465 {
466     return (boolean) (find_symbol(typedef_names, name) != NULL);
467 }
468 
469 /* If the matched text contains any new line characters, then update the
470  * current line number.
471  */
472 static void
473 update_line_num(void)
474 {
475     char *p = yytext;
476     while (*p != '\0') {
477 	if (*p++ == '\n')
478 	    cur_file->line_num++;
479     }
480 }
481 
482 /* Save the matched text in the temporary file.
483  */
484 static void
485 save_text(void)
486 {
487 #if OPT_LINTLIBRARY
488     if (!in_cpp)
489 	copy_typedef(yytext);
490 #endif
491     if (cur_file->convert) {
492 	fputs(yytext, cur_file->tmp_file);
493     }
494 }
495 
496 /* Record the current position in the temporary file and write the matched text
497  * to the file.
498  */
499 static void
500 save_text_offset(void)
501 {
502     (void) strcpy(yylval.text.text, yytext);
503 #if OPT_LINTLIBRARY
504     copy_typedef(yytext);
505 #endif
506     if (cur_file->convert) {
507 	yylval.text.begin = ftell(cur_file->tmp_file);
508 	fputs(yytext, cur_file->tmp_file);
509     } else
510 	yylval.text.begin = 0;
511 }
512 
513 #if OPT_LINTLIBRARY
514 /* Decipher comments that are useful for lint (and making lint-libraries)
515  */
516 static struct {
517     int varText;
518     int varargs;
519     int externs;
520     int preproz;
521 } cmtVal;
522 
523 static int
524 decipher_comment(char *keyword, int len)
525 {
526     if (len != 0) {
527 	int value;
528 	keyword[len] = '\0';
529 
530 	/* these are recognized by some lint-programs */
531 	if (!strcmp(keyword, "VARARGS")) {
532 	    cmtVal.varargs = -1;
533 	} else if (sscanf(keyword, "VARARGS%d", &value) == 1) {
534 	    cmtVal.varargs = value;
535 	} else if (!strcmp(keyword, "PRINTFLIKE")) {
536 	    cmtVal.varargs = 1;
537 	    cmtVal.varText = TRUE;
538 	} else if (sscanf(keyword, "PRINTFLIKE%d", &value) == 1) {
539 	    cmtVal.varargs = value;
540 	    cmtVal.varText = TRUE;
541 	} else if (!strcmp(keyword, "SCANFLIKE")) {
542 	    cmtVal.varargs = 2;
543 	    cmtVal.varText = TRUE;
544 	} else if (sscanf(keyword, "SCANFLIKE%d", &value) == 1) {
545 	    cmtVal.varargs = value;
546 	    cmtVal.varText = TRUE;
547 	    /* these are extensions added to simplify library-generation */
548 	} else if (!strcmp(keyword, "LINT_EXTERN")) {
549 	    cmtVal.externs = MAX_INC_DEPTH;
550 	} else if (sscanf(keyword, "LINT_EXTERN%d", &value) == 1) {
551 	    cmtVal.externs = value;
552 	} else if (!strcmp(keyword, "LINT_PREPRO")) {
553 	    cmtVal.preproz = -1;	/* the whole comment */
554 	} else if (sscanf(keyword, "LINT_PREPRO%d", &value) == 1) {
555 	    cmtVal.preproz = value;
556 	} else if (!strcmp(keyword, "LINT_SHADOWED")) {
557 	    lint_shadowed = TRUE;
558 	}
559     }
560     return 0;
561 }
562 #endif
563 
564 static void
565 put_quoted(int c)
566 {
567     /* Modifying 'yytext[]' doesn't work well with FLEX, which simply
568      * maintains 'yytext' as a pointer into its input buffer.  LEX copies
569      * characters into the 'yytext[]' array.
570      */
571 #if defined(FLEX_SCANNER) || !defined(YYLMAX)
572     if (c != 0) {
573 	static char temp[2];
574 	temp[0] = (char) c;
575 	/* save_text */
576 # if OPT_LINTLIBRARY
577 	if (!in_cpp)
578 	    copy_typedef(temp);
579 # endif
580 	if (cur_file->convert) {
581 	    fputs(temp, cur_file->tmp_file);
582 	}
583 	/* update_line_num */
584 	if (c == '\n')
585 	    cur_file->line_num++;
586     }
587 #else /* this works fine on LEX (e.g., on SunOS 4.x) */
588 
589     if ((c == 0) || (yyleng + 1 >= YYLMAX)) {
590 	save_text();
591 	update_line_num();
592 	yyleng = 0;
593     }
594     if (c != 0) {
595 	yytext[yyleng++] = c;
596 	yytext[yyleng] = 0;
597     }
598 #endif /* LEX/FLEX */
599 }
600 
601 /*
602  * Scan past the characters in a backslash sequence
603  */
604 /* Scan past quoted string.  Note that some strings may overflow 'yytext[]', so
605  * we don't try to eat them in the lexical rules.
606  */
607 static void
608 get_quoted(void)
609 {
610     int delim = *yytext;
611     int c;
612 
613 #if defined(FLEX_SCANNER) || !defined(YYLMAX)
614     put_quoted(delim);
615 #endif
616     while ((c = LexInput()) != 0) {
617 	if (c == '\\') {
618 	    put_quoted(c);
619 	    if ((c = LexInput()) == 0)
620 		break;
621 	    put_quoted(c);
622 	} else {
623 	    put_quoted(c);
624 	    if (c == delim)
625 		break;
626 	    if (c == '\n') {	/* recover from unbalanced */
627 		put_error();
628 		fprintf(stderr, "unbalanced quote character '%c'\n", delim);
629 		break;
630 	    }
631 	}
632     }
633     put_quoted(0);
634 }
635 
636 /* Scan to end of comment.
637  */
638 static void
639 get_comment(void)
640 {
641     int c, lastc = '\0';
642 
643 #if OPT_LINTLIBRARY
644     unsigned len = 0;
645     char keyword[BUFSIZ];
646 
647     keyword[len] = '\0';
648     cmtVal.varText = 0;
649     cmtVal.varargs = 0;
650     cmtVal.externs = -1;
651     cmtVal.preproz = 0;
652 #endif
653 
654     while ((c = LexInput()) != 0) {
655 	if (cur_file->convert)
656 	    fputc(c, cur_file->tmp_file);
657 
658 #if OPT_LINTLIBRARY
659 	if (!(isalnum(c) || c == '_' || c == '$')) {
660 	    int flag = cmtVal.preproz;
661 	    len = (unsigned) decipher_comment(keyword, (int) len);
662 	    if (flag != cmtVal.preproz)
663 		lastc = '\0';
664 	} else if (len + 1 < sizeof(keyword)) {
665 	    keyword[len++] = (char) c;
666 	}
667 #endif
668 
669 	switch (c) {
670 	case '\n':
671 	    cur_file->line_num++;
672 #if OPT_LINTLIBRARY
673 	    if (cmtVal.preproz != 0 && lastc != '\0')
674 		fputc(lastc, stdout);
675 	    if (cmtVal.preproz > 0)	/* if negative, we pass everything */
676 		cmtVal.preproz -= 1;
677 #endif
678 	    break;
679 	case '/':
680 	    if (lastc == '*') {
681 		if (cur_file->convert) {
682 		    if (func_params && cur_declarator) {
683 			cur_declarator->begin_comment = cur_file->begin_comment;
684 			cur_file->begin_comment = ftell(cur_file->tmp_file);
685 			cur_declarator->end_comment = cur_file->begin_comment;
686 			cur_declarator = NULL;
687 		    } else {
688 			cur_file->end_comment = ftell(cur_file->tmp_file);
689 		    }
690 		}
691 #if OPT_LINTLIBRARY
692 		(void) decipher_comment(keyword, (int) len);
693 		if (cmtVal.varargs != 0) {
694 		    if ((varargs_num = cmtVal.varargs) != 0
695 			&& cmtVal.varText != 0) {
696 			if (varargs_str != 0)
697 			    free(varargs_str);
698 			varargs_str = xstrdup(keyword);
699 		    }
700 		}
701 		if (cmtVal.externs >= 0)
702 		    extern_in = (unsigned) cmtVal.externs;
703 		if (cmtVal.preproz != 0)
704 		    fputc('\n', stdout);
705 #endif
706 		return;
707 	    }
708 	    /* FALLTHRU */
709 	default:
710 #if OPT_LINTLIBRARY
711 	    if (cmtVal.preproz != 0 && lastc != '\0')
712 		fputc(lastc, stdout);
713 #endif
714 	    break;
715 	}
716 	lastc = c;
717     }
718 }
719 
720 /* Scan rest of preprocessor directive.  If copy is true, then store the text
721  * in temp_buf.
722  */
723 static void
724 get_cpp_directive(int copy)
725 {
726     unsigned used = 0;
727     char c, lastc[4];
728 
729     lastc[0] = lastc[1] = lastc[2] = lastc[3] = '\0';
730     if (copy) {
731 	need_temp((size_t) 2);
732 	*temp_buf = '\0';
733     }
734 
735     while ((c = (char) LexInput()) != 0) {
736 	if (cur_file->convert)
737 	    fputc(c, cur_file->tmp_file);
738 
739 	switch (c) {
740 	case '\n':
741 	    cur_file->line_num++;
742 	    if (lastc[2] != '\\' && strcmp(lastc, "?\?/") != 0) {
743 		finishCpp();
744 		return;
745 	    }
746 	    break;
747 	case '*':
748 	    if (lastc[2] == '/')
749 		get_comment();
750 	    break;
751 	}
752 	lastc[0] = lastc[1];
753 	lastc[1] = lastc[2];
754 	lastc[2] = c;
755 
756 	if (copy) {
757 	    if (used + 2 >= temp_len)
758 		need_temp(temp_len + MAX_TEXT_SIZE);
759 	    temp_buf[used++] = c;
760 	    temp_buf[used] = '\0';
761 	}
762     }
763 }
764 
765 /*
766  * Ensure that the filename buffer is large enough to hold yytext, e.g., if
767  * the sscanf gave the whole buffer.
768  */
769 static void
770 parsing_file_name(unsigned need)
771 {
772     need += 2;
773     if (cur_file->len_file_name < need) {
774 	cur_file->len_file_name += need;
775 	cur_file->file_name = (char *) xrealloc(cur_file->file_name, cur_file->len_file_name);
776     }
777     cur_file->file_name[0] = 0;
778 }
779 
780 /* Return a pointer to the current file name.
781  */
782 char *
783 cur_file_name(void)
784 {
785     return cur_file->file_name;
786 }
787 
788 /* Return the current line number.
789  */
790 unsigned
791 cur_line_num(void)
792 {
793     return cur_file->line_num;
794 }
795 
796 /* Return the current temporary output file.
797  */
798 FILE *
799 cur_tmp_file(void)
800 {
801     return cur_file->tmp_file;
802 }
803 
804 /* Set the modify flag for the current file.
805  */
806 void
807 cur_file_changed(void)
808 {
809     cur_file->changed = TRUE;
810 }
811 
812 /* Return the temporary file offset of beginning of the current comment.
813  */
814 long
815 cur_begin_comment(void)
816 {
817     return cur_file->begin_comment;
818 }
819 
820 /* Return the text of the current lexical token.
821  */
822 char *
823 cur_text(void)
824 {
825     return yytext;
826 }
827 
828 #if !HAVE_TMPFILE
829 /*
830  * tmpfile() - return a FILE* for a temporary file that will be
831  * removed automatically when the program exits.
832  *
833  * Not all systems have the ANSI tmpfile() function yet...
834  *
835  * David W. Sanderson (dws@cs.wisc.edu)
836  *
837  * note - this was in version 3.10 from 1993 - TD
838  */
839 FILE *
840 tmpfile(void)
841 {
842     char *name;
843     char *tmpdir;
844     FILE *f;
845 
846     if ((tmpdir = getenv("TMPDIR")) == (char *) 0) {
847 	tmpdir = "/tmp";
848     }
849     name = xmalloc(strlen(tmpdir) + 20);
850     sprintf(name, "%s/TfXXXXXX", tmpdir);
851     call_mktemp(name);
852 
853     if ((f = fopen(name, "w+")) != 0) {
854 	if (unlink(name) == -1) {
855 	    fclose(f);
856 	    f = 0;
857 	}
858     }
859     free(name);
860     return f;
861 }
862 #endif /* !HAVE_TMPFILE */
863 
864 /* Push a file onto the include stack.	The stream yyin must already
865  * point to the file.
866  */
867 static void
868 include_file(char *name,	/* file name */
869 	     int convert)	/* if TRUE, convert function definitions */
870 {
871     if (++inc_depth >= (int) inc_limit) {
872 	unsigned need = (inc_limit | 31) + 1;
873 #ifdef FLEX_SCANNER
874 	buffer_stack = type_realloc(YY_BUFFER_STATE, buffer_stack, need);
875 #endif
876 	inc_stack = type_realloc(IncludeStack, inc_stack, need);
877 	while (inc_limit < need) {
878 #ifdef FLEX_SCANNER
879 	    buffer_stack[inc_limit] = 0;
880 #endif
881 	    memset(inc_stack + inc_limit, 0, sizeof(*inc_stack));
882 	    ++inc_limit;
883 	}
884     }
885 
886     cur_file = inc_stack + inc_depth;
887     cur_file->file = yyin;
888     cur_file->base_name = xstrdup(name);
889     cur_file->len_file_name = strlen(name) + MAX_TEXT_SIZE;
890     cur_file->file_name = strcpy((char *) xmalloc(cur_file->len_file_name), name);
891     cur_file->line_num = 1;
892     cur_file->convert = (boolean) convert;
893     cur_file->changed = FALSE;
894 
895 #ifdef FLEX_SCANNER
896     buffer_stack[inc_depth] = yy_create_buffer(yyin, YY_BUF_SIZE);
897     yy_switch_to_buffer(buffer_stack[inc_depth]);
898 #endif
899 
900     if (convert) {
901 	cur_file->begin_comment = cur_file->end_comment = 0;
902 	cur_file->tmp_file = tmpfile();
903 	if (cur_file->tmp_file == NULL) {
904 	    fprintf(stderr, "%s: cannot create temporary file\n", progname);
905 	    cur_file->convert = FALSE;
906 	}
907     }
908 }
909 
910 #define BLOCK_SIZE 2048
911 
912 /* Copy converted C source from the temporary file to the output stream.
913  */
914 static void
915 put_file(FILE *outf)
916 {
917     char block[BLOCK_SIZE];
918     long filesize;
919     size_t nread, count;
920 
921     filesize = ftell(cur_file->tmp_file);
922     fseek(cur_file->tmp_file, 0L, 0);
923     while (filesize > 0) {
924 	count = (filesize < BLOCK_SIZE) ? (size_t) filesize : BLOCK_SIZE;
925 	nread = fread(block, sizeof(char), count, cur_file->tmp_file);
926 	if (nread == 0)
927 	    break;
928 	fwrite(block, sizeof(char), nread, outf);
929 	filesize -= (long) nread;
930     }
931 }
932 
933 /* Remove the top of the include stack.
934  */
935 void
936 pop_file(int closed)
937 {
938     FILE *outf;
939 
940     if (!closed && (yyin != stdin))
941 	fclose(yyin);
942 
943     if (cur_file->convert) {
944 	if (yyin == stdin) {
945 	    put_file(stdout);
946 	} else if (cur_file->changed) {
947 	    if ((outf = fopen(cur_file->base_name, "w")) != NULL) {
948 		put_file(outf);
949 		fclose(outf);
950 	    } else {
951 		fprintf(stderr, "%s: cannot create file %s\n", progname,
952 			cur_file->base_name);
953 	    }
954 	}
955 
956 	fclose(cur_file->tmp_file);
957     }
958     free(cur_file->base_name);
959     free(cur_file->file_name);
960 
961 #ifdef FLEX_SCANNER
962     yy_delete_buffer(YY_CURRENT_BUFFER);
963 #endif
964 
965     if (--inc_depth >= 0) {
966 	cur_file = inc_stack + inc_depth;
967 	yyin = cur_file->file;
968 
969 #ifdef FLEX_SCANNER
970 	yy_switch_to_buffer(buffer_stack[inc_depth]);
971 #endif
972     }
973 }
974 
975 /* Process include directive.
976  */
977 static void
978 do_include(char *file_spec)	/* path surrounded by "" or <> */
979 {
980     unsigned stdinc;		/* 1 = path surrounded by <> */
981     char *file;
982     char *path;
983     char match, *s;
984     unsigned i;
985     unsigned n;
986     FILE *fp;
987 
988     if (file_spec[0] == '"') {
989 	match = '"';
990 	stdinc = 0;
991     } else if (file_spec[0] == '<') {
992 	match = '>';
993 	stdinc = 1;
994     } else {
995 	return;
996     }
997     s = strchr(file_spec + 1, match);
998     n = (s != NULL) ? (unsigned) (s - file_spec - 1) : 0;
999     file = xstrdup(file_spec + 1);
1000     file[n] = '\0';
1001 
1002     /* Do nothing if the file was already included. */
1003     path = (char *) xmalloc(strlen(file) + 3);
1004     sprintf(path, stdinc ? "<%s>" : "\"%s\"", file);
1005     if (find_symbol(included_files, path) == NULL) {
1006 	new_symbol(included_files, path, NULL, DS_NONE);
1007 
1008 	for (i = (unsigned) (stdinc != 0); i < num_inc_dir; ++i) {
1009 	    if (strlen(inc_dir[i]) == 0 || !strcmp(inc_dir[i], CURRENT_DIR)) {
1010 		strcpy(path, file);
1011 	    } else {
1012 		path = (char *) xrealloc(path, strlen(file) +
1013 					 strlen(inc_dir[i]) + 2);
1014 		sprintf(path, "%s/%s", inc_dir[i], file);
1015 	    }
1016 	    if ((fp = fopen(path, "r")) != NULL) {
1017 		yyin = fp;
1018 		include_file(path, func_style != FUNC_NONE && !stdinc);
1019 		free(file);
1020 		free(path);
1021 		return;
1022 	    }
1023 	}
1024 
1025 	if (!quiet) {
1026 	    put_error();
1027 	    fprintf(stderr, "cannot read file %s\n", file_spec);
1028 	}
1029     }
1030     free(file);
1031     free(path);
1032 }
1033 
1034 /* When the end of the current input file is reached, pop a
1035  * nested include file.
1036  */
1037 int
1038 yywrap(void)
1039 {
1040     if (inc_depth > 0) {
1041 	pop_file(FALSE);
1042 	return 0;
1043     } else {
1044 	return 1;
1045     }
1046 }
1047 
1048 #ifdef NO_LEAKS
1049 void
1050 free_lexer(void)
1051 {
1052     if (inc_limit != 0) {
1053 #ifdef FLEX_SCANNER
1054 	free(buffer_stack);
1055 #endif
1056 	free(inc_stack);
1057     }
1058 }
1059 #endif
1060