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