xref: /onnv-gate/usr/src/cmd/fm/eversholt/common/esclex.c (revision 8245:7dbd13b3b276)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52869Sgavinm  * Common Development and Distribution License (the "License").
62869Sgavinm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
226277Scy152378  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * esclex.c -- lexer for esc
260Sstevel@tonic-gate  *
270Sstevel@tonic-gate  * this module provides lexical analysis and error handling routine
280Sstevel@tonic-gate  * expected by the yacc-generated parser (i.e. yylex() and yyerror()).
290Sstevel@tonic-gate  * it also does lots of tracking of things like filenames, line numbers,
300Sstevel@tonic-gate  * and what tokens are seen on a line up to the point where a syntax error
310Sstevel@tonic-gate  * was found.  this module also arranges for the input source files to
320Sstevel@tonic-gate  * be run through cpp.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <ctype.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <unistd.h>
400Sstevel@tonic-gate #include <time.h>
410Sstevel@tonic-gate #include <errno.h>
420Sstevel@tonic-gate #include "out.h"
430Sstevel@tonic-gate #include "alloc.h"
440Sstevel@tonic-gate #include "stats.h"
450Sstevel@tonic-gate #include "stable.h"
460Sstevel@tonic-gate #include "lut.h"
470Sstevel@tonic-gate #include "literals.h"
480Sstevel@tonic-gate #include "tree.h"
490Sstevel@tonic-gate #include "esclex.h"
500Sstevel@tonic-gate #include "eftread.h"
510Sstevel@tonic-gate #include "check.h"
520Sstevel@tonic-gate #include "y.tab.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /* ridiculously long token buffer -- disallow any token longer than this */
550Sstevel@tonic-gate #define	MAXTOK	8192
560Sstevel@tonic-gate static char Tok[MAXTOK];
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /* some misc stats we keep on the lexer & parser */
590Sstevel@tonic-gate static struct stats *Tokcount;
600Sstevel@tonic-gate static struct stats *Lexelapse;
610Sstevel@tonic-gate struct stats *Filecount;
620Sstevel@tonic-gate struct filestats {
630Sstevel@tonic-gate 	struct filestats *next;
640Sstevel@tonic-gate 	struct stats *stats;
652869Sgavinm 	struct stats *idstats;
660Sstevel@tonic-gate } *Fstats;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static int Errcount;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /* input file state */
710Sstevel@tonic-gate static char **Files;
720Sstevel@tonic-gate static const char *Fileopened;
730Sstevel@tonic-gate static FILE *Fp;
740Sstevel@tonic-gate static int Line;
750Sstevel@tonic-gate static const char *File;
760Sstevel@tonic-gate static const char *Cpp = "/usr/bin/cpp";
770Sstevel@tonic-gate #ifdef	ESC
780Sstevel@tonic-gate static const char *Cppargs;
790Sstevel@tonic-gate static const char *Cppstdargs = "-undef -Y.";
800Sstevel@tonic-gate #endif	/* ESC */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* for debugging */
830Sstevel@tonic-gate static int Lexecho;	/* echo tokens as we read them */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /* forward declarations of our internal routines */
860Sstevel@tonic-gate static int record(int tok, const char *s);
870Sstevel@tonic-gate static void dumpline(int flags);
880Sstevel@tonic-gate static void doident();
890Sstevel@tonic-gate static void dopragma(const char *tok);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * table of reserved words.  this table is only used by lex_init()
930Sstevel@tonic-gate  * to intialize the Rwords lookup table.
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate static const struct {
960Sstevel@tonic-gate 	const char *word;
970Sstevel@tonic-gate 	const int val;
980Sstevel@tonic-gate } Rwords[] = {
990Sstevel@tonic-gate 	{ "asru", ASRU },
1001414Scindi 	{ "count", COUNT },
1010Sstevel@tonic-gate 	{ "div", DIV },
1020Sstevel@tonic-gate 	{ "engine", ENGINE },
1030Sstevel@tonic-gate 	{ "event", EVENT },
1040Sstevel@tonic-gate 	{ "fru", FRU },
1050Sstevel@tonic-gate 	{ "if", IF },
1060Sstevel@tonic-gate 	{ "mask", MASK },
1070Sstevel@tonic-gate 	{ "prop", PROP },
1080Sstevel@tonic-gate 	{ "config", CONFIG },
1090Sstevel@tonic-gate 	/*
1100Sstevel@tonic-gate 	 * PATHFUNC indicates functions that operate only on paths
1110Sstevel@tonic-gate 	 * and quotes
1120Sstevel@tonic-gate 	 */
1130Sstevel@tonic-gate 	{ "is_connected", PATHFUNC },
1140Sstevel@tonic-gate 	{ "is_under", PATHFUNC },
1157197Sstephh 	{ "is_on", PATHFUNC },
1167197Sstephh 	{ "is_present", PATHFUNC },
1177197Sstephh 	{ "is_type", PATHFUNC },
118*8245SStephen.Hanson@Sun.COM 	{ "has_fault", PATHFUNC },
1197197Sstephh 	{ "confprop", PATHFUNC },
1207197Sstephh 	{ "confprop_defined", PATHFUNC },
1210Sstevel@tonic-gate };
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate  * Rwordslut is a lookup table of reserved words.  lhs is the word
1250Sstevel@tonic-gate  * (in the string table) and the rhs is the token value returned
1260Sstevel@tonic-gate  * by the yylex() for that word.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate static struct lut *Rwordslut;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static const struct {
1310Sstevel@tonic-gate 	const char *suffix;
1320Sstevel@tonic-gate 	const unsigned long long nsec;
1330Sstevel@tonic-gate } Timesuffix[] = {
1340Sstevel@tonic-gate 	{ "nanosecond",		1ULL },
1350Sstevel@tonic-gate 	{ "nanoseconds",	1ULL },
1360Sstevel@tonic-gate 	{ "nsec",		1ULL },
1370Sstevel@tonic-gate 	{ "nsecs",		1ULL },
1380Sstevel@tonic-gate 	{ "ns",			1ULL },
1390Sstevel@tonic-gate 	{ "microsecond",	1000ULL },
1400Sstevel@tonic-gate 	{ "microseconds",	1000ULL },
1410Sstevel@tonic-gate 	{ "usec",		1000ULL },
1420Sstevel@tonic-gate 	{ "usecs",		1000ULL },
1430Sstevel@tonic-gate 	{ "us",			1000ULL },
1440Sstevel@tonic-gate 	{ "millisecond",	1000000ULL },
1450Sstevel@tonic-gate 	{ "milliseconds",	1000000ULL },
1460Sstevel@tonic-gate 	{ "msec",		1000000ULL },
1470Sstevel@tonic-gate 	{ "msecs",		1000000ULL },
1480Sstevel@tonic-gate 	{ "ms",			1000000ULL },
1490Sstevel@tonic-gate 	{ "second",		1000000000ULL },
1500Sstevel@tonic-gate 	{ "seconds",		1000000000ULL },
1510Sstevel@tonic-gate 	{ "s",			1000000000ULL },
1520Sstevel@tonic-gate 	{ "minute",		1000000000ULL * 60 },
1530Sstevel@tonic-gate 	{ "minutes",		1000000000ULL * 60 },
1540Sstevel@tonic-gate 	{ "min",		1000000000ULL * 60 },
1550Sstevel@tonic-gate 	{ "mins",		1000000000ULL * 60 },
1560Sstevel@tonic-gate 	{ "m",			1000000000ULL * 60 },
1570Sstevel@tonic-gate 	{ "hour",		1000000000ULL * 60 * 60 },
1580Sstevel@tonic-gate 	{ "hours",		1000000000ULL * 60 * 60 },
1590Sstevel@tonic-gate 	{ "hr",			1000000000ULL * 60 * 60 },
1600Sstevel@tonic-gate 	{ "hrs",		1000000000ULL * 60 * 60 },
1610Sstevel@tonic-gate 	{ "h",			1000000000ULL * 60 * 60 },
1620Sstevel@tonic-gate 	{ "day",		1000000000ULL * 60 * 60 * 24 },
1630Sstevel@tonic-gate 	{ "days",		1000000000ULL * 60 * 60 * 24 },
1640Sstevel@tonic-gate 	{ "d",			1000000000ULL * 60 * 60 * 24 },
1650Sstevel@tonic-gate 	{ "week",		1000000000ULL * 60 * 60 * 24 * 7 },
1660Sstevel@tonic-gate 	{ "weeks",		1000000000ULL * 60 * 60 * 24 * 7 },
1670Sstevel@tonic-gate 	{ "wk",			1000000000ULL * 60 * 60 * 24 * 7 },
1680Sstevel@tonic-gate 	{ "wks",		1000000000ULL * 60 * 60 * 24 * 7 },
1690Sstevel@tonic-gate 	{ "month",		1000000000ULL * 60 * 60 * 24 * 30 },
1700Sstevel@tonic-gate 	{ "months",		1000000000ULL * 60 * 60 * 24 * 30 },
1710Sstevel@tonic-gate 	{ "year",		1000000000ULL * 60 * 60 * 24 * 365 },
1720Sstevel@tonic-gate 	{ "years",		1000000000ULL * 60 * 60 * 24 * 365 },
1730Sstevel@tonic-gate 	{ "yr",			1000000000ULL * 60 * 60 * 24 * 365 },
1740Sstevel@tonic-gate 	{ "yrs",		1000000000ULL * 60 * 60 * 24 * 365 },
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * some wrappers around the general lut functions to provide type checking...
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate static struct lut *
lex_s2i_lut_add(struct lut * root,const char * s,intptr_t i)1826277Scy152378 lex_s2i_lut_add(struct lut *root, const char *s, intptr_t i)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	return (lut_add(root, (void *)s, (void *)i, NULL));
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate static int
lex_s2i_lut_lookup(struct lut * root,const char * s)1880Sstevel@tonic-gate lex_s2i_lut_lookup(struct lut *root, const char *s)
1890Sstevel@tonic-gate {
1906277Scy152378 	return ((intptr_t)lut_lookup(root, (void *)s, NULL));
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static struct lut *
lex_s2ullp_lut_add(struct lut * root,const char * s,const unsigned long long * ullp)1940Sstevel@tonic-gate lex_s2ullp_lut_add(struct lut *root, const char *s,
1950Sstevel@tonic-gate     const unsigned long long *ullp)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	return (lut_add(root, (void *)s, (void *)ullp, NULL));
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate const unsigned long long *
lex_s2ullp_lut_lookup(struct lut * root,const char * s)2010Sstevel@tonic-gate lex_s2ullp_lut_lookup(struct lut *root, const char *s)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	return ((unsigned long long *)lut_lookup(root, (void *)s, NULL));
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate /*
2070Sstevel@tonic-gate  * lex_init -- initialize the lexer with appropriate filenames & debug flags
2080Sstevel@tonic-gate  */
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*ARGSUSED*/
2110Sstevel@tonic-gate void
lex_init(char ** av,const char * cppargs,int lexecho)2120Sstevel@tonic-gate lex_init(char **av, const char *cppargs, int lexecho)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	int i;
2150Sstevel@tonic-gate #ifdef	ESC
2160Sstevel@tonic-gate 	const char *ptr;
2170Sstevel@tonic-gate #endif	/* ESC */
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	Lexecho = lexecho;
2200Sstevel@tonic-gate 	Tokcount = stats_new_counter("lex.tokens", "total tokens in", 1);
2210Sstevel@tonic-gate 	Filecount = stats_new_counter("lex.files", "total files read", 0);
2220Sstevel@tonic-gate 	Lexelapse = stats_new_elapse("lex.time", "elapsed lex/parse time", 1);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate #ifdef	ESC
2250Sstevel@tonic-gate 	Cppargs = cppargs;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/* allow user to tell us where cpp is if it is some weird place */
2280Sstevel@tonic-gate 	if (ptr = getenv("_ESC_CPP"))
2290Sstevel@tonic-gate 		Cpp = ptr;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/* and in case it takes some special stdargs */
2320Sstevel@tonic-gate 	if (ptr = getenv("_ESC_CPP_STDARGS"))
2330Sstevel@tonic-gate 		Cppstdargs = ptr;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* verify we can find cpp */
2360Sstevel@tonic-gate 	if (access(Cpp, X_OK) < 0) {
2370Sstevel@tonic-gate 		Cpp = "/usr/lib/cpp";
2380Sstevel@tonic-gate 		if (access(Cpp, X_OK) < 0)
2390Sstevel@tonic-gate 			out(O_DIE, "can't locate cpp");
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate #endif	/* ESC */
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	Files = av;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* verify we can find all the input files */
2460Sstevel@tonic-gate 	while (*av) {
2470Sstevel@tonic-gate 		if (strlen(*av) >= MAXTOK - strlen(Cpp) - 3)
2480Sstevel@tonic-gate 			out(O_DIE, "filename too long: %.100s...", *av);
2490Sstevel@tonic-gate 		if (access(*av, R_OK) < 0)
2500Sstevel@tonic-gate 			out(O_DIE|O_SYS, "%s", *av);
2510Sstevel@tonic-gate 		av++;
2520Sstevel@tonic-gate 		stats_counter_bump(Filecount);
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	/* put reserved words into the string table & a lookup table */
2560Sstevel@tonic-gate 	for (i = 0; i < sizeof (Rwords) / sizeof (*Rwords); i++)
2570Sstevel@tonic-gate 		Rwordslut = lex_s2i_lut_add(Rwordslut,
2580Sstevel@tonic-gate 		    stable(Rwords[i].word), Rwords[i].val);
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/* initialize table of timeval suffixes */
2610Sstevel@tonic-gate 	for (i = 0; i < sizeof (Timesuffix) / sizeof (*Timesuffix); i++) {
2620Sstevel@tonic-gate 		Timesuffixlut = lex_s2ullp_lut_add(Timesuffixlut,
2630Sstevel@tonic-gate 		    stable(Timesuffix[i].suffix), &Timesuffix[i].nsec);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/* record start time */
2670Sstevel@tonic-gate 	stats_elapse_start(Lexelapse);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate void
closefile(void)2710Sstevel@tonic-gate closefile(void)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	if (Fp != NULL) {
2740Sstevel@tonic-gate #ifdef	ESC
2750Sstevel@tonic-gate 		if (pclose(Fp) > 0)
2760Sstevel@tonic-gate 			out(O_DIE, "cpp errors while reading \"%s\", "
2770Sstevel@tonic-gate 			    "bailing out.", Fileopened);
2780Sstevel@tonic-gate #else
2790Sstevel@tonic-gate 		(void) fclose(Fp);
2800Sstevel@tonic-gate #endif	/* ESC */
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 	Fp = NULL;
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate  * yylex -- the lexer, called yylex() because that's what yacc wants
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate int
yylex()2900Sstevel@tonic-gate yylex()
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	int c;
2930Sstevel@tonic-gate 	int nextc;
2940Sstevel@tonic-gate 	char *ptr = Tok;
2950Sstevel@tonic-gate 	char *eptr = &Tok[MAXTOK];
2960Sstevel@tonic-gate 	const char *cptr;
2970Sstevel@tonic-gate 	int startline;
2980Sstevel@tonic-gate 	int val;
2990Sstevel@tonic-gate 	static int bol = 1;	/* true if we're at beginning of line */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	for (;;) {
3020Sstevel@tonic-gate 		while (Fp == NULL) {
3032869Sgavinm 			char ibuf[80];
3042869Sgavinm 
3050Sstevel@tonic-gate 			if (*Files == NULL)
3060Sstevel@tonic-gate 				return (record(EOF, NULL));
3070Sstevel@tonic-gate 			Fileopened = stable(*Files++);
3080Sstevel@tonic-gate #ifdef	ESC
3090Sstevel@tonic-gate 			sprintf(Tok, "%s %s %s %s",
3100Sstevel@tonic-gate 			    Cpp, Cppstdargs, Cppargs, Fileopened);
3110Sstevel@tonic-gate 			if ((Fp = popen(Tok, "r")) == NULL)
3120Sstevel@tonic-gate 				out(O_DIE|O_SYS, "%s", Tok);
3130Sstevel@tonic-gate #else
3142869Sgavinm 			Fp = eftread_fopen(Fileopened, ibuf, sizeof (ibuf));
3150Sstevel@tonic-gate #endif	/* ESC */
3160Sstevel@tonic-gate 			Line = 1;
3170Sstevel@tonic-gate 			bol = 1;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 			/* add name to stats for visibility */
3200Sstevel@tonic-gate 			if (Fp != NULL) {
3210Sstevel@tonic-gate 				static int fnum;
3220Sstevel@tonic-gate 				char nbuf[100];
3230Sstevel@tonic-gate 				struct filestats *nfs = MALLOC(sizeof (*nfs));
3242869Sgavinm 
3252869Sgavinm 				(void) sprintf(nbuf, "lex.file%d", fnum);
3260Sstevel@tonic-gate 				nfs->stats = stats_new_string(nbuf, "", 0);
3270Sstevel@tonic-gate 				stats_string_set(nfs->stats, Fileopened);
3282869Sgavinm 
3292869Sgavinm 				if (ibuf[0] != '\0') {
3302869Sgavinm 					(void) sprintf(nbuf, "lex.file%d-ident",
3312869Sgavinm 					    fnum);
3322869Sgavinm 					nfs->idstats =
3332869Sgavinm 					    stats_new_string(nbuf, "", 0);
3342869Sgavinm 					stats_string_set(nfs->idstats, ibuf);
3352869Sgavinm 				} else {
3362869Sgavinm 					nfs->idstats = NULL;
3372869Sgavinm 				}
3382869Sgavinm 
3390Sstevel@tonic-gate 				nfs->next = Fstats;
3400Sstevel@tonic-gate 				Fstats = nfs;
3412869Sgavinm 				fnum++;
3420Sstevel@tonic-gate 			}
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		switch (c = getc(Fp)) {
3460Sstevel@tonic-gate 		case '#':
3470Sstevel@tonic-gate 			/* enforce that we're at beginning of line */
3480Sstevel@tonic-gate 			if (!bol)
3490Sstevel@tonic-gate 				return (record(c, NULL));
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 			while ((c = getc(Fp)) != EOF &&
3520Sstevel@tonic-gate 			    (c == ' ' || c == '\t'))
3530Sstevel@tonic-gate 				;
3540Sstevel@tonic-gate 			if (!isdigit(c)) {
3550Sstevel@tonic-gate 				/*
3560Sstevel@tonic-gate 				 * three cases here:
3570Sstevel@tonic-gate 				 *	#pragma
3580Sstevel@tonic-gate 				 *	#ident
3590Sstevel@tonic-gate 				 *	#something-we-don't-understand
3600Sstevel@tonic-gate 				 * anything we don't expect we just ignore.
3610Sstevel@tonic-gate 				 */
3620Sstevel@tonic-gate 				*ptr++ = c;
3630Sstevel@tonic-gate 				while ((c = getc(Fp)) != EOF && isalnum(c))
3640Sstevel@tonic-gate 					if (ptr < eptr - 1)
3650Sstevel@tonic-gate 						*ptr++ = c;
3660Sstevel@tonic-gate 				*ptr++ = '\0';
3670Sstevel@tonic-gate 				if (strcmp(Tok, "pragma") == 0) {
3680Sstevel@tonic-gate 					/* skip white space */
3690Sstevel@tonic-gate 					while ((c = getc(Fp)) != EOF &&
3700Sstevel@tonic-gate 					    (c == ' ' || c == '\t'))
3710Sstevel@tonic-gate 						;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 					if (c == EOF || c == '\n')
3740Sstevel@tonic-gate 						outfl(O_DIE, File, Line,
3750Sstevel@tonic-gate 						    "bad #pragma");
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 					/* pull in next token */
3780Sstevel@tonic-gate 					ptr = Tok;
3790Sstevel@tonic-gate 					*ptr++ = c;
3800Sstevel@tonic-gate 					while ((c = getc(Fp)) != EOF &&
3810Sstevel@tonic-gate 					    !isspace(c))
3820Sstevel@tonic-gate 						if (ptr < eptr - 1)
3830Sstevel@tonic-gate 							*ptr++ = c;
3840Sstevel@tonic-gate 					*ptr++ = '\0';
3850Sstevel@tonic-gate 					(void) ungetc(c, Fp);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 					dopragma(Tok);
3880Sstevel@tonic-gate 				} else if (strcmp(Tok, "ident") == 0)
3890Sstevel@tonic-gate 					doident();
3900Sstevel@tonic-gate 			} else {
3910Sstevel@tonic-gate 				/* handle file & line info from cpp */
3920Sstevel@tonic-gate 				Line = 0;
3930Sstevel@tonic-gate 				do {
3940Sstevel@tonic-gate 					if (!isdigit(c))
3950Sstevel@tonic-gate 						break;
3960Sstevel@tonic-gate 					Line = Line * 10 + c - '0';
3970Sstevel@tonic-gate 				} while ((c = getc(Fp)) != EOF);
3980Sstevel@tonic-gate 				Line--;		/* newline will increment it */
3990Sstevel@tonic-gate 				while (c != EOF && isspace(c))
4000Sstevel@tonic-gate 					c = getc(Fp);
4010Sstevel@tonic-gate 				if (c != '"')
4020Sstevel@tonic-gate 					outfl(O_DIE, File, Line,
4030Sstevel@tonic-gate 					    "bad # statement (file name)");
4040Sstevel@tonic-gate 				while ((c = getc(Fp)) != EOF && c != '"')
4050Sstevel@tonic-gate 					if (ptr < eptr - 1)
4060Sstevel@tonic-gate 						*ptr++ = c;
4070Sstevel@tonic-gate 				*ptr++ = '\0';
4080Sstevel@tonic-gate 				if (c != '"')
4090Sstevel@tonic-gate 					outfl(O_DIE, File, Line,
4100Sstevel@tonic-gate 					    "bad # statement (quotes)");
4110Sstevel@tonic-gate 				File = stable(Tok);
4120Sstevel@tonic-gate 			}
4130Sstevel@tonic-gate 			/* skip the rest of the cpp line */
4140Sstevel@tonic-gate 			while ((c = getc(Fp)) != EOF && c != '\n' && c != '\r')
4150Sstevel@tonic-gate 				;
4160Sstevel@tonic-gate 			if (c == EOF)
4170Sstevel@tonic-gate 				return (record(c, NULL));
4180Sstevel@tonic-gate 			else
4190Sstevel@tonic-gate 				(void) ungetc(c, Fp);
4200Sstevel@tonic-gate 			ptr = Tok;
4210Sstevel@tonic-gate 			break;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		case EOF:
4240Sstevel@tonic-gate 			closefile();
4250Sstevel@tonic-gate 			continue;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		case '\n':
4280Sstevel@tonic-gate 			Line++;
4290Sstevel@tonic-gate 			bol = 1;
4300Sstevel@tonic-gate 			break;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		case '\r':
4330Sstevel@tonic-gate 		case ' ':
4340Sstevel@tonic-gate 		case '\t':
4350Sstevel@tonic-gate 			bol = 0;
4360Sstevel@tonic-gate 			break;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		case '/':
4390Sstevel@tonic-gate 			bol = 0;
4400Sstevel@tonic-gate 			/* comment handling */
4410Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == EOF)
4420Sstevel@tonic-gate 				outfl(O_DIE, File, Line, "unexpected EOF");
4430Sstevel@tonic-gate 			else if (nextc == '*') {
4440Sstevel@tonic-gate 				startline = Line;
4450Sstevel@tonic-gate 				while ((c = getc(Fp)) != EOF) {
4460Sstevel@tonic-gate 					if (c == '\n')
4470Sstevel@tonic-gate 						Line++;
4480Sstevel@tonic-gate 					else if (c == '*' &&
4496277Scy152378 					    (((c = getc(Fp)) == EOF) ||
4506277Scy152378 					    (c == '/')))
4510Sstevel@tonic-gate 						break;
4520Sstevel@tonic-gate 				}
4530Sstevel@tonic-gate 				if (c == EOF) {
4540Sstevel@tonic-gate 					outfl(O_DIE, File, Line,
4550Sstevel@tonic-gate 					    "end of comment not seen "
4560Sstevel@tonic-gate 					    "(started on line %d)",
4570Sstevel@tonic-gate 					    startline);
4580Sstevel@tonic-gate 				}
4590Sstevel@tonic-gate 			} else {
4600Sstevel@tonic-gate 				/* wasn't a comment, return the '/' token */
4610Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
4620Sstevel@tonic-gate 				return (record(c, NULL));
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 			break;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		case '"': {
4670Sstevel@tonic-gate 			int prevc;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 			bol = 0;
4700Sstevel@tonic-gate 			prevc = '\0';
4710Sstevel@tonic-gate 			/* quoted string handling */
4720Sstevel@tonic-gate 			startline = Line;
4730Sstevel@tonic-gate 			for (;;) {
4740Sstevel@tonic-gate 				c = getc(Fp);
4750Sstevel@tonic-gate 				if (c == EOF)
4760Sstevel@tonic-gate 					outfl(O_DIE, File, Line,
4770Sstevel@tonic-gate 					    "end of string not seen "
4780Sstevel@tonic-gate 					    "(started on line %d)",
4790Sstevel@tonic-gate 					    startline);
4800Sstevel@tonic-gate 				else if (c == '\n')
4810Sstevel@tonic-gate 					Line++;
4820Sstevel@tonic-gate 				else if (c == '"' && prevc != '\\')
4830Sstevel@tonic-gate 					break;
4840Sstevel@tonic-gate 				else if (ptr < eptr)
4850Sstevel@tonic-gate 					*ptr++ = c;
4860Sstevel@tonic-gate 				prevc = c;
4870Sstevel@tonic-gate 			}
4880Sstevel@tonic-gate 			if (ptr >= eptr)
4890Sstevel@tonic-gate 				out(O_DIE, File, Line, "string too long");
4900Sstevel@tonic-gate 			*ptr++ = '\0';
4910Sstevel@tonic-gate 			return (record(QUOTE, stable(Tok)));
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 		case '&':
4940Sstevel@tonic-gate 			bol = 0;
4950Sstevel@tonic-gate 			/* && */
4960Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '&')
4970Sstevel@tonic-gate 				return (record(AND, NULL));
4980Sstevel@tonic-gate 			else {
4990Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5000Sstevel@tonic-gate 				return (record(c, NULL));
5010Sstevel@tonic-gate 			}
5020Sstevel@tonic-gate 			/*NOTREACHED*/
5030Sstevel@tonic-gate 			break;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		case '|':
5060Sstevel@tonic-gate 			bol = 0;
5070Sstevel@tonic-gate 			/* || */
5080Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '|')
5090Sstevel@tonic-gate 				return (record(OR, NULL));
5100Sstevel@tonic-gate 			else {
5110Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5120Sstevel@tonic-gate 				return (record(c, NULL));
5130Sstevel@tonic-gate 			}
5140Sstevel@tonic-gate 			/*NOTREACHED*/
5150Sstevel@tonic-gate 			break;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		case '!':
5180Sstevel@tonic-gate 			bol = 0;
5190Sstevel@tonic-gate 			/* ! or != */
5200Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '=')
5210Sstevel@tonic-gate 				return (record(NE, NULL));
5220Sstevel@tonic-gate 			else {
5230Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5240Sstevel@tonic-gate 				return (record(c, NULL));
5250Sstevel@tonic-gate 			}
5260Sstevel@tonic-gate 			/*NOTREACHED*/
5270Sstevel@tonic-gate 			break;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 		case '=':
5300Sstevel@tonic-gate 			bol = 0;
5310Sstevel@tonic-gate 			/* == */
5320Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '=')
5330Sstevel@tonic-gate 				return (record(EQ, NULL));
5340Sstevel@tonic-gate 			else {
5350Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5360Sstevel@tonic-gate 				return (record(c, NULL));
5370Sstevel@tonic-gate 			}
5380Sstevel@tonic-gate 			/*NOTREACHED*/
5390Sstevel@tonic-gate 			break;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 		case '-':
5420Sstevel@tonic-gate 			bol = 0;
5430Sstevel@tonic-gate 			/* -> */
5440Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '>')
5450Sstevel@tonic-gate 				return (record(ARROW, stable(Tok)));
5460Sstevel@tonic-gate 			else {
5470Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5480Sstevel@tonic-gate 				return (record(c, NULL));
5490Sstevel@tonic-gate 			}
5500Sstevel@tonic-gate 			/*NOTREACHED*/
5510Sstevel@tonic-gate 			break;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		case '<':
5540Sstevel@tonic-gate 			bol = 0;
5550Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '=')
5560Sstevel@tonic-gate 				/* <= */
5570Sstevel@tonic-gate 				return (record(LE, NULL));
5580Sstevel@tonic-gate 			else if (nextc == '<')
5590Sstevel@tonic-gate 				/* << */
5600Sstevel@tonic-gate 				return (record(LSHIFT, NULL));
5610Sstevel@tonic-gate 			else {
5620Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5630Sstevel@tonic-gate 				return (record(c, NULL));
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 			/*NOTREACHED*/
5660Sstevel@tonic-gate 			break;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		case '>':
5690Sstevel@tonic-gate 			bol = 0;
5700Sstevel@tonic-gate 			if ((nextc = getc(Fp)) == '=')
5710Sstevel@tonic-gate 				/* >= */
5720Sstevel@tonic-gate 				return (record(GE, NULL));
5730Sstevel@tonic-gate 			else if (nextc == '>')
5740Sstevel@tonic-gate 				/* >> */
5750Sstevel@tonic-gate 				return (record(RSHIFT, NULL));
5760Sstevel@tonic-gate 			else {
5770Sstevel@tonic-gate 				(void) ungetc(nextc, Fp);
5780Sstevel@tonic-gate 				return (record(c, NULL));
5790Sstevel@tonic-gate 			}
5800Sstevel@tonic-gate 			/*NOTREACHED*/
5810Sstevel@tonic-gate 			break;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		default:
5840Sstevel@tonic-gate 			bol = 0;
5850Sstevel@tonic-gate 			if (isdigit(c)) {
5860Sstevel@tonic-gate 				int base;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 				/* collect rest of number */
5890Sstevel@tonic-gate 				if (c == '0') {
5900Sstevel@tonic-gate 					*ptr++ = c;
5910Sstevel@tonic-gate 					if ((c = getc(Fp)) == EOF) {
5920Sstevel@tonic-gate 						*ptr++ = '\0';
5930Sstevel@tonic-gate 						return (record(NUMBER,
5940Sstevel@tonic-gate 						    stable(Tok)));
5950Sstevel@tonic-gate 					} else if (c == 'x' || c == 'X') {
5960Sstevel@tonic-gate 						*ptr++ = c;
5970Sstevel@tonic-gate 						base = 16;
5980Sstevel@tonic-gate 					} else {
5990Sstevel@tonic-gate 						(void) ungetc(c, Fp);
6000Sstevel@tonic-gate 						base = 8;
6010Sstevel@tonic-gate 					}
6020Sstevel@tonic-gate 				} else {
6030Sstevel@tonic-gate 					*ptr++ = c;
6040Sstevel@tonic-gate 					base = 10;
6050Sstevel@tonic-gate 				}
6060Sstevel@tonic-gate 				while ((c = getc(Fp)) != EOF) {
6070Sstevel@tonic-gate 					if (ptr >= eptr)
6080Sstevel@tonic-gate 						out(O_DIE, File, Line,
6090Sstevel@tonic-gate 						    "number too long");
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 					switch (base) {
6120Sstevel@tonic-gate 					case 16:
6130Sstevel@tonic-gate 						if (c >= 'a' && c <= 'f' ||
6140Sstevel@tonic-gate 						    c >= 'A' && c <= 'F') {
6150Sstevel@tonic-gate 							*ptr++ = c;
6160Sstevel@tonic-gate 							continue;
6170Sstevel@tonic-gate 						}
6180Sstevel@tonic-gate 						/*FALLTHRU*/
6190Sstevel@tonic-gate 					case 10:
6200Sstevel@tonic-gate 						if (c >= '8' && c <= '9') {
6210Sstevel@tonic-gate 							*ptr++ = c;
6220Sstevel@tonic-gate 							continue;
6230Sstevel@tonic-gate 						}
6240Sstevel@tonic-gate 						/*FALLTHRU*/
6250Sstevel@tonic-gate 					case 8:
6260Sstevel@tonic-gate 						if (c >= '0' && c <= '7') {
6270Sstevel@tonic-gate 							*ptr++ = c;
6280Sstevel@tonic-gate 							continue;
6290Sstevel@tonic-gate 						}
6300Sstevel@tonic-gate 						/* not valid for this base */
6310Sstevel@tonic-gate 						*ptr++ = '\0';
6320Sstevel@tonic-gate 						(void) ungetc(c, Fp);
6330Sstevel@tonic-gate 						return (record(NUMBER,
6340Sstevel@tonic-gate 						    stable(Tok)));
6350Sstevel@tonic-gate 					}
6360Sstevel@tonic-gate 				}
6370Sstevel@tonic-gate 				*ptr++ = '\0';
6380Sstevel@tonic-gate 				return (record(NUMBER, stable(Tok)));
6390Sstevel@tonic-gate 			} else if (isalpha(c)) {
6400Sstevel@tonic-gate 				/* collect identifier */
6410Sstevel@tonic-gate 				*ptr++ = c;
6420Sstevel@tonic-gate 				for (;;) {
6430Sstevel@tonic-gate 					c = getc(Fp);
6440Sstevel@tonic-gate 					if ((isalnum(c) || c == '_') &&
6456277Scy152378 					    ptr < eptr)
6460Sstevel@tonic-gate 						*ptr++ = c;
6470Sstevel@tonic-gate 					else {
6480Sstevel@tonic-gate 						(void) ungetc(c, Fp);
6490Sstevel@tonic-gate 						break;
6500Sstevel@tonic-gate 					}
6510Sstevel@tonic-gate 				}
6520Sstevel@tonic-gate 				if (ptr >= eptr)
6530Sstevel@tonic-gate 					out(O_DIE, File, Line,
6540Sstevel@tonic-gate 					    "identifier too long");
6550Sstevel@tonic-gate 				*ptr++ = '\0';
6560Sstevel@tonic-gate 				cptr = stable(Tok);
6570Sstevel@tonic-gate 				if (val = lex_s2i_lut_lookup(Rwordslut, cptr)) {
6580Sstevel@tonic-gate 					return (record(val, cptr));
6590Sstevel@tonic-gate 				}
6600Sstevel@tonic-gate 				return (record(ID, cptr));
6610Sstevel@tonic-gate 			} else
6620Sstevel@tonic-gate 				return (record(c, NULL));
6630Sstevel@tonic-gate 		}
6640Sstevel@tonic-gate 		/*NOTREACHED*/
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate  * the record()/dumpline() routines are used to track & report
6700Sstevel@tonic-gate  * the list of tokens seen on a given line.  this is used in two ways.
6710Sstevel@tonic-gate  * first, syntax errors found by the parser are reported by us (via
6720Sstevel@tonic-gate  * yyerror()) and we tack on the tokens processed so far on the current
6730Sstevel@tonic-gate  * line to help indicate exactly where the error is.  second, if "lexecho"
6740Sstevel@tonic-gate  * debugging is turned on, these routines provide it.
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate #define	MAXRECORD 1000
6770Sstevel@tonic-gate static int Recordedline;
6780Sstevel@tonic-gate static struct {
6790Sstevel@tonic-gate 	int tok;
6800Sstevel@tonic-gate 	const char *s;
6810Sstevel@tonic-gate } Recorded[MAXRECORD];
6820Sstevel@tonic-gate static int Recordnext;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate static int
record(int tok,const char * s)6850Sstevel@tonic-gate record(int tok, const char *s)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	stats_counter_bump(Tokcount);
6880Sstevel@tonic-gate 	if (Line != Recordedline) {
6890Sstevel@tonic-gate 		/* starting new line, dump out the previous line */
6900Sstevel@tonic-gate 		if (Lexecho && Recordedline) {
6910Sstevel@tonic-gate 			outfl(O_NONL, File, Recordedline, "lex: ");
6920Sstevel@tonic-gate 			dumpline(O_OK);
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		Recordedline = Line;
6950Sstevel@tonic-gate 		Recordnext = 0;
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 	if (Recordnext >= MAXRECORD)
6980Sstevel@tonic-gate 		outfl(O_DIE, File, Line, "line too long, bailing out");
6990Sstevel@tonic-gate 	Recorded[Recordnext].tok = tok;
7000Sstevel@tonic-gate 	Recorded[Recordnext++].s = s;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	yylval.tok.s = s;
7030Sstevel@tonic-gate 	yylval.tok.file = File;
7040Sstevel@tonic-gate 	yylval.tok.line = Line;
7050Sstevel@tonic-gate 	return (tok);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*ARGSUSED*/
7090Sstevel@tonic-gate static void
dumpline(int flags)7100Sstevel@tonic-gate dumpline(int flags)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 	int i;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	for (i = 0; i < Recordnext; i++)
7150Sstevel@tonic-gate 		if (Recorded[i].s && Recorded[i].tok != ARROW)
7160Sstevel@tonic-gate 			switch (Recorded[i].tok) {
7170Sstevel@tonic-gate 			case T_QUOTE:
7180Sstevel@tonic-gate 				out(flags|O_NONL, " \"%s\"",
7196277Scy152378 				    Recorded[i].s);
7200Sstevel@tonic-gate 				break;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 			default:
7230Sstevel@tonic-gate 				out(flags|O_NONL, " %s",
7246277Scy152378 				    Recorded[i].s);
7250Sstevel@tonic-gate 				break;
7260Sstevel@tonic-gate 			}
7270Sstevel@tonic-gate 		else
7280Sstevel@tonic-gate 			switch (Recorded[i].tok) {
7290Sstevel@tonic-gate 			case EOF:
7300Sstevel@tonic-gate 				out(flags|O_NONL, " EOF");
7310Sstevel@tonic-gate 				break;
7320Sstevel@tonic-gate 			case ARROW:
7330Sstevel@tonic-gate 				out(flags|O_NONL, " ->%s",
7346277Scy152378 				    Recorded[i].s);
7350Sstevel@tonic-gate 				break;
7360Sstevel@tonic-gate 			case EQ:
7370Sstevel@tonic-gate 				out(flags|O_NONL, " ==");
7380Sstevel@tonic-gate 				break;
7390Sstevel@tonic-gate 			case NE:
7400Sstevel@tonic-gate 				out(flags|O_NONL, " !=");
7410Sstevel@tonic-gate 				break;
7420Sstevel@tonic-gate 			case OR:
7430Sstevel@tonic-gate 				out(flags|O_NONL, " ||");
7440Sstevel@tonic-gate 				break;
7450Sstevel@tonic-gate 			case AND:
7460Sstevel@tonic-gate 				out(flags|O_NONL, " &&");
7470Sstevel@tonic-gate 				break;
7480Sstevel@tonic-gate 			case LE:
7490Sstevel@tonic-gate 				out(flags|O_NONL, " <=");
7500Sstevel@tonic-gate 				break;
7510Sstevel@tonic-gate 			case GE:
7520Sstevel@tonic-gate 				out(flags|O_NONL, " >=");
7530Sstevel@tonic-gate 				break;
7540Sstevel@tonic-gate 			case LSHIFT:
7550Sstevel@tonic-gate 				out(flags|O_NONL, " <<");
7560Sstevel@tonic-gate 				break;
7570Sstevel@tonic-gate 			case RSHIFT:
7580Sstevel@tonic-gate 				out(flags|O_NONL, " >>");
7590Sstevel@tonic-gate 				break;
7600Sstevel@tonic-gate 			default:
7610Sstevel@tonic-gate 				if (isprint(Recorded[i].tok))
7620Sstevel@tonic-gate 					out(flags|O_NONL, " %c",
7636277Scy152378 					    Recorded[i].tok);
7640Sstevel@tonic-gate 				else
7650Sstevel@tonic-gate 					out(flags|O_NONL, " '\\%03o'",
7666277Scy152378 					    Recorded[i].tok);
7670Sstevel@tonic-gate 				break;
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 	out(flags, NULL);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate  * yyerror -- report a pareser error, called yyerror because yacc wants it
7740Sstevel@tonic-gate  */
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate void
yyerror(const char * s)7770Sstevel@tonic-gate yyerror(const char *s)
7780Sstevel@tonic-gate {
7790Sstevel@tonic-gate 	Errcount++;
7800Sstevel@tonic-gate 	outfl(O_ERR|O_NONL, File, Line, "%s, tokens: ", s);
7810Sstevel@tonic-gate 	dumpline(O_ERR);
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate /*
7850Sstevel@tonic-gate  * doident -- handle "#pragma ident" directives
7860Sstevel@tonic-gate  */
7870Sstevel@tonic-gate static void
doident()7880Sstevel@tonic-gate doident()
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	int c;
7910Sstevel@tonic-gate 	char *ptr = Tok;
7920Sstevel@tonic-gate 	char *eptr = &Tok[MAXTOK];
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	/* skip white space and quotes */
7950Sstevel@tonic-gate 	while ((c = getc(Fp)) != EOF &&
7960Sstevel@tonic-gate 	    (c == ' ' || c == '\t' || c == '"'))
7970Sstevel@tonic-gate 		;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	if (c == EOF || c == '\n')
8000Sstevel@tonic-gate 		outfl(O_DIE, File, Line, "bad ident");
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	/* pull in next token */
8030Sstevel@tonic-gate 	ptr = Tok;
8040Sstevel@tonic-gate 	*ptr++ = c;
8050Sstevel@tonic-gate 	while ((c = getc(Fp)) != EOF && c != '"' && c != '\n')
8060Sstevel@tonic-gate 		if (ptr < eptr - 1)
8070Sstevel@tonic-gate 			*ptr++ = c;
8080Sstevel@tonic-gate 	*ptr++ = '\0';
8090Sstevel@tonic-gate 	if (c != '\n') {
8100Sstevel@tonic-gate 		/* skip to end of line (including close quote, if any) */
8110Sstevel@tonic-gate 		while ((c = getc(Fp)) != EOF && c != '\n')
8120Sstevel@tonic-gate 			;
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 	(void) ungetc(c, Fp);
8150Sstevel@tonic-gate 	Ident = lut_add(Ident, (void *)stable(Tok), (void *)0, NULL);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	outfl(O_VERB, File, Line, "pragma set: ident \"%s\"", Tok);
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate /*
8210Sstevel@tonic-gate  * dodictionary -- handle "#pragma dictionary" directives
8220Sstevel@tonic-gate  */
8230Sstevel@tonic-gate static void
dodictionary()8240Sstevel@tonic-gate dodictionary()
8250Sstevel@tonic-gate {
8260Sstevel@tonic-gate 	int c;
8270Sstevel@tonic-gate 	char *ptr = Tok;
8280Sstevel@tonic-gate 	char *eptr = &Tok[MAXTOK];
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/* skip white space and quotes */
8310Sstevel@tonic-gate 	while ((c = getc(Fp)) != EOF &&
8320Sstevel@tonic-gate 	    (c == ' ' || c == '\t' || c == '"'))
8330Sstevel@tonic-gate 		;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	if (c == EOF || c == '\n')
8360Sstevel@tonic-gate 		outfl(O_DIE, File, Line, "bad dictionary");
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/* pull in next token */
8390Sstevel@tonic-gate 	ptr = Tok;
8400Sstevel@tonic-gate 	*ptr++ = c;
8410Sstevel@tonic-gate 	while ((c = getc(Fp)) != EOF && c != '"' && c != '\n')
8420Sstevel@tonic-gate 		if (ptr < eptr - 1)
8430Sstevel@tonic-gate 			*ptr++ = c;
8440Sstevel@tonic-gate 	*ptr++ = '\0';
8450Sstevel@tonic-gate 	if (c != '\n') {
8460Sstevel@tonic-gate 		/* skip to end of line (including close quote, if any) */
8470Sstevel@tonic-gate 		while ((c = getc(Fp)) != EOF && c != '\n')
8480Sstevel@tonic-gate 			;
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 	(void) ungetc(c, Fp);
8510Sstevel@tonic-gate 	Dicts = lut_add(Dicts, (void *)stable(Tok), (void *)0, NULL);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	outfl(O_VERB, File, Line, "pragma set: dictionary \"%s\"", Tok);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate  * doallow_cycles -- handle "#pragma allow_cycles" directives
8580Sstevel@tonic-gate  */
8590Sstevel@tonic-gate static void
doallow_cycles()8600Sstevel@tonic-gate doallow_cycles()
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	int c;
8630Sstevel@tonic-gate 	char *ptr = Tok;
8640Sstevel@tonic-gate 	char *eptr = &Tok[MAXTOK];
8650Sstevel@tonic-gate 	unsigned long long newlevel;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * by default the compiler does not allow cycles or loops
8690Sstevel@tonic-gate 	 * in propagations.  when cycles are encountered, the
8700Sstevel@tonic-gate 	 * compiler prints out an error message.
8710Sstevel@tonic-gate 	 *
8720Sstevel@tonic-gate 	 *   "#pragma allow_cycles" and
8730Sstevel@tonic-gate 	 *   "#pragma allow_cycles 0"
8740Sstevel@tonic-gate 	 * allow cycles, but any such cycle will produce a warning
8750Sstevel@tonic-gate 	 * message.
8760Sstevel@tonic-gate 	 *
8770Sstevel@tonic-gate 	 *   "#pragma allow_cycles N"
8780Sstevel@tonic-gate 	 * with N > 0 will allow cycles and not produce any
8790Sstevel@tonic-gate 	 * warning messages.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/* skip white space and quotes */
8830Sstevel@tonic-gate 	while ((c = getc(Fp)) != EOF &&
8840Sstevel@tonic-gate 	    (c == ' ' || c == '\t' || c == '"'))
8850Sstevel@tonic-gate 		;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	if (c == EOF || c == '\n')
8880Sstevel@tonic-gate 		newlevel = 0ULL;
8890Sstevel@tonic-gate 	else {
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		/* pull in next token */
8920Sstevel@tonic-gate 		ptr = Tok;
8930Sstevel@tonic-gate 		*ptr++ = c;
8940Sstevel@tonic-gate 		while ((c = getc(Fp)) != EOF && c != '"' && c != '\n')
8950Sstevel@tonic-gate 			if (ptr < eptr - 1)
8960Sstevel@tonic-gate 				*ptr++ = c;
8970Sstevel@tonic-gate 		*ptr++ = '\0';
8980Sstevel@tonic-gate 		if (c != '\n') {
8990Sstevel@tonic-gate 			/* skip to end of line */
9000Sstevel@tonic-gate 			while ((c = getc(Fp)) != EOF && c != '\n')
9010Sstevel@tonic-gate 				;
9020Sstevel@tonic-gate 		}
9030Sstevel@tonic-gate 		newlevel = strtoll(Tok, NULL, 0);
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 	(void) ungetc(c, Fp);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	(void) check_cycle_level(newlevel);
9080Sstevel@tonic-gate 	outfl(O_VERB, File, Line,
9090Sstevel@tonic-gate 	    "pragma set: allow_cycles (%s)",
9106277Scy152378 	    newlevel ? "no warnings" : "with warnings");
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate  * dopragma -- handle #pragma directives
9150Sstevel@tonic-gate  */
9160Sstevel@tonic-gate static void
dopragma(const char * tok)9170Sstevel@tonic-gate dopragma(const char *tok)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate 	if (strcmp(tok, "ident") == 0)
9200Sstevel@tonic-gate 		doident();
9210Sstevel@tonic-gate 	else if (strcmp(tok, "dictionary") == 0)
9220Sstevel@tonic-gate 		dodictionary();
9230Sstevel@tonic-gate 	else if (strcmp(tok, "new_errors_only") == 0) {
9240Sstevel@tonic-gate 		if (Pragma_new_errors_only++ == 0)
9250Sstevel@tonic-gate 			outfl(O_VERB, File, Line,
9260Sstevel@tonic-gate 			    "pragma set: new_errors_only");
9270Sstevel@tonic-gate 	} else if (strcmp(tok, "trust_ereports") == 0) {
9280Sstevel@tonic-gate 		if (Pragma_trust_ereports++ == 0)
9290Sstevel@tonic-gate 			outfl(O_VERB, File, Line,
9300Sstevel@tonic-gate 			    "pragma set: trust_ereports");
9310Sstevel@tonic-gate 	} else if (strcmp(tok, "allow_cycles") == 0)
9320Sstevel@tonic-gate 		doallow_cycles();
9330Sstevel@tonic-gate 	else
9340Sstevel@tonic-gate 		outfl(O_VERB, File, Line,
9350Sstevel@tonic-gate 		    "unknown pragma ignored: \"%s\"", tok);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate /*
9390Sstevel@tonic-gate  * lex_fini -- finalize the lexer
9400Sstevel@tonic-gate  */
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate int
lex_fini(void)9430Sstevel@tonic-gate lex_fini(void)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	stats_elapse_stop(Lexelapse);
9460Sstevel@tonic-gate 	closefile();
9470Sstevel@tonic-gate 	if (Lexecho) {
9480Sstevel@tonic-gate 		outfl(O_OK, File, Line, "lex: ");
9490Sstevel@tonic-gate 		dumpline(O_OK);
9500Sstevel@tonic-gate 	}
9510Sstevel@tonic-gate 	return (Errcount);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate void
lex_free(void)9550Sstevel@tonic-gate lex_free(void)
9560Sstevel@tonic-gate {
9570Sstevel@tonic-gate 	struct filestats *nfstats = Fstats;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/*
9600Sstevel@tonic-gate 	 * Free up memory consumed by the lexer
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 	stats_delete(Tokcount);
9630Sstevel@tonic-gate 	stats_delete(Filecount);
9640Sstevel@tonic-gate 	stats_delete(Lexelapse);
9650Sstevel@tonic-gate 	while (nfstats != NULL) {
9660Sstevel@tonic-gate 		Fstats = nfstats->next;
9670Sstevel@tonic-gate 		stats_delete(nfstats->stats);
9682869Sgavinm 		if (nfstats->idstats != NULL)
9692869Sgavinm 			stats_delete(nfstats->idstats);
9700Sstevel@tonic-gate 		FREE(nfstats);
9710Sstevel@tonic-gate 		nfstats = Fstats;
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 	lut_free(Timesuffixlut, NULL, NULL);
9740Sstevel@tonic-gate 	lut_free(Rwordslut, NULL, NULL);
9750Sstevel@tonic-gate 	lut_free(Ident, NULL, NULL);
9760Sstevel@tonic-gate 	lut_free(Dicts, NULL, NULL);
9770Sstevel@tonic-gate }
978