/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #pragma ident "%Z%%M% %I% %E% SMI" #include "dextern.h" static void go2gen(int); static void precftn(int, int, int); static void wract(int); static void wrstate(int); static void wdef(wchar_t *, int); static void wrmbchars(void); /* important local variables */ static int lastred; /* number of the last reduction of a state */ int *defact; extern int *toklev; extern int cwp; /* print the output for the states */ void output() { int i, k, c; register WSET *u, *v; (void) fprintf(ftable, "static YYCONST yytabelem yyexca[] ={\n"); SLOOP(i) { /* output the stuff for state i */ nolook = !(tystate[i] == MUSTLOOKAHEAD); closure(i); /* output actions */ nolook = 1; aryfil(temp1, ntoksz+nnontersz+1, 0); WSLOOP(wsets, u) { c = *(u->pitem); if (c > 1 && c < NTBASE && temp1[c] == 0) { WSLOOP(u, v) { if (c == *(v->pitem)) putitem(v->pitem + 1, (LOOKSETS *)0); } temp1[c] = state(c); } else if (c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0) { temp1[c + ntokens] = amem[indgo[i] + c]; } } if (i == 1) temp1[1] = ACCEPTCODE; /* now, we have the shifts; look at the reductions */ lastred = 0; WSLOOP(wsets, u) { c = *(u->pitem); if (c <= 0) { /* reduction */ lastred = -c; TLOOP(k) { if (BIT(u->ws.lset, k)) { if (temp1[k] == 0) temp1[k] = c; else if (temp1[k] < 0) { /* * reduce/reduce * conflict */ /* BEGIN CSTYLED */ if (foutput != NULL) (void) fprintf(foutput, WSFMT("\n%d: reduce/reduce conflict" " (red'ns %d and %d ) on %ws"), i, -temp1[k], lastred, symnam(k)); if (-temp1[k] > lastred) temp1[k] = -lastred; ++zzrrconf; /* END CSTYLED */ } else /* * potentia * shift/reduce * conflict. */ precftn(lastred, k, i); } } } } wract(i); } (void) fprintf(ftable, "\t};\n"); wdef(L"YYNPROD", nprod); if (nmbchars > 0) { wrmbchars(); } } static int pkdebug = 0; int apack(p, n) int *p; int n; { /* pack state i from temp1 into amem */ int off; int *pp, *qq; int *q, *rr; int diff; /* * we don't need to worry about checking because we * we will only look up entries known to be there... */ /* eliminate leading and trailing 0's */ q = p + n; for (pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off) /* NULL */; if (pp > q) return (0); /* no actions */ p = pp; /* now, find a place for the elements from p to q, inclusive */ /* for( rr=amem; rr<=r; ++rr,++off ){ */ /* try rr */ rr = amem; for (; ; ++rr, ++off) { while (rr >= &amem[new_actsize-1]) exp_act(&rr); qq = rr; for (pp = p; pp <= q; ++pp, ++qq) { if (*pp) { diff = qq - rr; while (qq >= &amem[new_actsize-1]) { exp_act(&rr); qq = diff + rr; } if (*pp != *qq && *qq != 0) goto nextk; } } /* we have found an acceptable k */ if (pkdebug && foutput != NULL) (void) fprintf(foutput, "off = %d, k = %" PRIdPTR "\n", off, rr-amem); qq = rr; for (pp = p; pp <= q; ++pp, ++qq) { if (*pp) { diff = qq - rr; while (qq >= &amem[new_actsize-1]) { exp_act(&rr); qq = diff + rr; } if (qq > memp) memp = qq; *qq = *pp; } } if (pkdebug && foutput != NULL) { for (pp = amem; pp <= memp; pp += 10) { (void) fprintf(foutput, "\t"); for (qq = pp; qq <= pp + 9; ++qq) (void) fprintf(foutput, "%d ", *qq); (void) fprintf(foutput, "\n"); } } return (off); nextk:; } /* error("no space in action table" ); */ /* NOTREACHED */ } void go2out() { /* output the gotos for the nontermninals */ int i, j, k, best, count, cbest, times; (void) fprintf(ftemp, "$\n"); /* mark begining of gotos */ for (i = 1; i <= nnonter; ++i) { go2gen(i); /* find the best one to make default */ best = -1; times = 0; for (j = 0; j < nstate; ++j) { /* is j the most frequent */ if (tystate[j] == 0) continue; if (tystate[j] == best) continue; /* is tystate[j] the most frequent */ count = 0; cbest = tystate[j]; for (k = j; k < nstate; ++k) if (tystate[k] == cbest) ++count; if (count > times) { best = cbest; times = count; } } /* best is now the default entry */ zzgobest += (times-1); for (j = 0; j < nstate; ++j) { if (tystate[j] != 0 && tystate[j] != best) { (void) fprintf(ftemp, "%d,%d,", j, tystate[j]); zzgoent += 1; } } /* now, the default */ zzgoent += 1; (void) fprintf(ftemp, "%d\n", best); } } static int g2debug = 0; static void go2gen(int c) { /* output the gotos for nonterminal c */ int i, work, cc; ITEM *p, *q; /* first, find nonterminals with gotos on c */ aryfil(temp1, nnonter + 1, 0); temp1[c] = 1; work = 1; while (work) { work = 0; PLOOP(0, i) { if ((cc = prdptr[i][1] - NTBASE) >= 0) { /* cc is a nonterminal */ if (temp1[cc] != 0) { /* * cc has a goto on c * thus, the left side of * production i does too. */ cc = *prdptr[i] - NTBASE; if (temp1[cc] == 0) { work = 1; temp1[cc] = 1; } } } } } /* now, we have temp1[c] = 1 if a goto on c in closure of cc */ if (g2debug && foutput != NULL) { (void) fprintf(foutput, WSFMT("%ws: gotos on "), nontrst[c].name); NTLOOP(i) if (temp1[i]) (void) fprintf(foutput, WSFMT("%ws "), nontrst[i].name); (void) fprintf(foutput, "\n"); } /* now, go through and put gotos into tystate */ aryfil(tystate, nstate, 0); SLOOP(i) { ITMLOOP(i, p, q) { if ((cc = *p->pitem) >= NTBASE) { if (temp1[cc -= NTBASE]) { /* goto on c is possible */ tystate[i] = amem[indgo[i] + c]; break; } } } } } /* decide a shift/reduce conflict by precedence. */ static void precftn(int r, int t, int s) { /* * r is a rule number, t a token number * the conflict is in state s * temp1[t] is changed to reflect the action */ int lp, lt, action; lp = levprd[r]; lt = toklev[t]; if (PLEVEL(lt) == 0 || PLEVEL(lp) == 0) { /* conflict */ if (foutput != NULL) (void) fprintf(foutput, WSFMT("\n%d: shift/reduce conflict" " (shift %d, red'n %d) on %ws"), s, temp1[t], r, symnam(t)); ++zzsrconf; return; } if (PLEVEL(lt) == PLEVEL(lp)) action = ASSOC(lt) & ~04; else if (PLEVEL(lt) > PLEVEL(lp)) action = RASC; /* shift */ else action = LASC; /* reduce */ switch (action) { case BASC: /* error action */ temp1[t] = ERRCODE; return; case LASC: /* reduce */ temp1[t] = -r; return; } } static void wract(int i) { /* output state i */ /* temp1 has the actions, lastred the default */ int p, p0, p1; int ntimes, tred, count, j; int flag; /* find the best choice for lastred */ lastred = 0; ntimes = 0; TLOOP(j) { if (temp1[j] >= 0) continue; if (temp1[j] + lastred == 0) continue; /* count the number of appearances of temp1[j] */ count = 0; tred = -temp1[j]; levprd[tred] |= REDFLAG; TLOOP(p) { if (temp1[p] + tred == 0) ++count; } if (count > ntimes) { lastred = tred; ntimes = count; } } /* * for error recovery, arrange that, if there is a shift on the * error recovery token, `error', that the default be the error action */ if (temp1[2] > 0) lastred = 0; /* clear out entries in temp1 which equal lastred */ TLOOP(p) { if (temp1[p] + lastred == 0) temp1[p] = 0; } wrstate(i); defact[i] = lastred; flag = 0; TLOOP(p0) { if ((p1 = temp1[p0]) != 0) { if (p1 < 0) { p1 = -p1; goto exc; } else if (p1 == ACCEPTCODE) { p1 = -1; goto exc; } else if (p1 == ERRCODE) { p1 = 0; goto exc; exc: if (flag++ == 0) (void) fprintf(ftable, "-1, %d,\n", i); (void) fprintf(ftable, "\t%d, %d,\n", tokset[p0].value, p1); ++zzexcp; } else { (void) fprintf(ftemp, "%d,%d,", tokset[p0].value, p1); ++zzacent; } } } if (flag) { defact[i] = -2; (void) fprintf(ftable, "\t-2, %d,\n", lastred); } (void) fprintf(ftemp, "\n"); } static void wrstate(int i) { /* writes state i */ int j0, j1; register ITEM *pp, *qq; register WSET *u; if (foutput == NULL) return; (void) fprintf(foutput, "\nstate %d\n", i); ITMLOOP(i, pp, qq) { (void) fprintf(foutput, WSFMT("\t%ws\n"), writem(pp->pitem)); } if (tystate[i] == MUSTLOOKAHEAD) { /* print out empty productions in closure */ WSLOOP(wsets + (pstate[i + 1] - pstate[i]), u) { if (*(u->pitem) < 0) (void) fprintf(foutput, WSFMT("\t%ws\n"), writem(u->pitem)); } } /* check for state equal to another */ TLOOP(j0) if ((j1 = temp1[j0]) != 0) { (void) fprintf(foutput, WSFMT("\n\t%ws "), symnam(j0)); if (j1 > 0) { /* shift, error, or accept */ if (j1 == ACCEPTCODE) (void) fprintf(foutput, "accept"); else if (j1 == ERRCODE) (void) fprintf(foutput, "error"); else (void) fprintf(foutput, "shift %d", j1); } else (void) fprintf(foutput, "reduce %d", -j1); } /* output the final production */ if (lastred) (void) fprintf(foutput, "\n\t. reduce %d\n\n", lastred); else (void) fprintf(foutput, "\n\t. error\n\n"); /* now, output nonterminal actions */ j1 = ntokens; for (j0 = 1; j0 <= nnonter; ++j0) { if (temp1[++j1]) (void) fprintf(foutput, WSFMT("\t%ws goto %d\n"), symnam(j0 + NTBASE), temp1[j1]); } } static void wdef(wchar_t *s, int n) { /* output a definition of s to the value n */ (void) fprintf(ftable, WSFMT("# define %ws %d\n"), s, n); } void warray(s, v, n) wchar_t *s; int *v, n; { int i; (void) fprintf(ftable, WSFMT("static YYCONST yytabelem %ws[]={\n"), s); for (i = 0; i < n; ) { if (i % 10 == 0) (void) fprintf(ftable, "\n"); (void) fprintf(ftable, "%6d", v[i]); if (++i == n) (void) fprintf(ftable, " };\n"); else (void) fprintf(ftable, ","); } } void hideprod() { /* * in order to free up the mem and amem arrays for the optimizer, * and still be able to output yyr1, etc., after the sizes of * the action array is known, we hide the nonterminals * derived by productions in levprd. */ int i, j; j = 0; levprd[0] = 0; PLOOP(1, i) { if (!(levprd[i] & REDFLAG)) { ++j; if (foutput != NULL) { (void) fprintf(foutput, WSFMT("Rule not reduced: %ws\n"), writem(prdptr[i])); } } levprd[i] = *prdptr[i] - NTBASE; } if (j) /* * TRANSLATION_NOTE -- This is a message from yacc. * Check how 'reduced' is translated in yacc man page/document. */ (void) fprintf(stderr, gettext("%d rules never reduced\n"), j); } static int cmpmbchars(p, q) MBCLIT *p, *q; { /* Compare two MBLITs. */ return ((p->character) - (q->character)); } static void wrmbchars() { int i; wdef(L"YYNMBCHARS", nmbchars); qsort(mbchars, nmbchars, sizeof (*mbchars), (int (*)(const void *, const void *))cmpmbchars); (void) fprintf(ftable, "static struct{\n\twchar_t character;" "\n\tint tvalue;\n}yymbchars[YYNMBCHARS]={\n"); for (i = 0; i < nmbchars; ++i) { (void) fprintf(ftable, "\t{%#x,%d}", (int)mbchars[i].character, mbchars[i].tvalue); if (i < nmbchars - 1) { /* Not the last. */ (void) fprintf(ftable, ",\n"); } } (void) fprintf(ftable, "\n};\n"); }