1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1988 AT&T	*/
27/*	All Rights Reserved	*/
28
29#pragma ident	"%Z%%M%	%I%	%E% SMI"
30
31#include "ldefs.h"
32#include <limits.h>
33
34/*
35 * return next line of input, throw away trailing '\n'
36 * and also throw away trailing blanks (spaces and tabs)
37 * returns 0 if eof is had immediately
38 */
39
40CHR *
41getl(CHR *p)
42{
43	int c;
44	CHR *s, *t, *u;
45	int blank = 0;
46
47	t = s = p;
48	while (((c = gch()) != 0) && c != '\n') {
49		if (t >= &p[BUF_SIZ])
50			error("definitions too long");
51		if (c == ' ' || c == '\t') {
52			if (!blank) {
53				blank = 1;
54				u = t;
55			}
56		} else
57			blank = 0;
58
59		*t++ = c;
60	}
61	if (blank)
62		*u = 0;
63	else
64		*t = 0;
65
66	if (c == 0 && s == t)
67		return ((CHR *) 0);
68	prev = '\n';
69	pres = '\n';
70	return (s);
71}
72
73int
74space(int ch)
75{
76	switch (ch) {
77		case ' ':
78		case '\t':
79		case '\n':
80			return (1);
81	}
82	return (0);
83}
84
85int
86digit(int c)
87{
88	return (c >= '0' && c <= '9');
89}
90
91/* VARARGS1 */
92void
93error(s, p, d)
94char *s;
95int p, d;
96{
97	/* if(!eof) */
98	if (!yyline)
99		(void) fprintf(errorf, "Command line: ");
100	else {
101		(void) fprintf(errorf,
102			!no_input ? "" : "\"%s\":", sargv[optind]);
103		(void) fprintf(errorf, "line %d: ", yyline);
104	}
105	(void) fprintf(errorf, "Error: ");
106	/*LINTED: E_SEC_PRINTF_VAR_FMT*/
107	(void) fprintf(errorf, s, p, d);
108	(void) putc('\n', errorf);
109	if (fatal)
110		error_tail();
111}
112
113void
114error_tail(void)
115{
116#ifdef DEBUG
117	if (debug && sect != ENDSECTION) {
118		sect1dump();
119		sect2dump();
120	}
121#endif
122
123	if (report == 1)
124		statistics();
125	exit(1);
126	/* NOTREACHED */
127}
128
129/* VARARGS1 */
130void
131warning(s, p, d)
132char *s;
133int p, d;
134{
135	if (!eof)
136		if (!yyline)
137			(void) fprintf(errorf, "Command line: ");
138		else {
139			(void) fprintf(errorf,
140				!no_input?"":"\"%s\":", sargv[optind]);
141			(void) fprintf(errorf,
142				"line %d: ", yyline);
143		}
144	(void) fprintf(errorf, "Warning: ");
145	/*LINTED: E_SEC_PRINTF_VAR_FMT*/
146	(void) fprintf(errorf, s, p, d);
147	(void) putc('\n', errorf);
148	(void) fflush(errorf);
149	if (fout)
150		(void) fflush(fout);
151	(void) fflush(stdout);
152}
153
154/*
155 * This function is apparently unused, but lint flags the fact
156 * that it does not have the same signature as the libc function
157 * of the same name. So, take it out of view for lint.
158 */
159#if !defined(__lint)
160int
161index(int a, CHR *s)
162{
163	int k;
164	for (k = 0; s[k]; k++)
165		if (s[k] == a)
166			return (k);
167	return (-1);
168}
169#endif
170
171int
172alpha(int c)
173{
174	return ('a' <= c && c <= 'z' ||
175	    'A' <= c && c <= 'Z');
176}
177
178int
179printable(int c)
180{
181	return (c > 040 && c < 0177);
182}
183
184void
185lgate(void)
186{
187	char fname[20];
188
189	if (lgatflg)
190		return;
191	lgatflg = 1;
192	if (fout == NULL) {
193		(void) sprintf(fname, "lex.yy.%c", ratfor ? 'r' : 'c');
194		fout = fopen(fname, "w");
195	}
196	if (fout == NULL)
197		error("Can't open %s", fname);
198	if (ratfor)
199		(void) fprintf(fout, "#\n");
200	phead1();
201}
202
203/*
204 * scopy(ptr to str, ptr to str) - copy first arg str to second
205 * returns ptr to second arg
206 */
207void
208scopy(CHR *s, CHR *t)
209{
210	CHR *i;
211	i = t;
212	while (*i++ = *s++)
213		;
214}
215
216/*
217 * convert string t, return integer value
218 */
219int
220siconv(CHR *t)
221{
222	int i, sw;
223	CHR *s;
224	s = t;
225	while (space(*s))
226		s++;
227	if (!digit(*s) && *s != '-')
228		error("missing translation value");
229	sw = 0;
230	if (*s == '-') {
231		sw = 1;
232		s++;
233	}
234	if (!digit(*s))
235		error("incomplete translation format");
236	i = 0;
237	while ('0' <= *s && *s <= '9')
238		i = i * 10 + (*(s++)-'0');
239	return (sw ? -i : i);
240}
241
242/*
243 * slength(ptr to str) - return integer length of string arg
244 * excludes '\0' terminator
245 */
246int
247slength(CHR *s)
248{
249	int n;
250	CHR *t;
251	t = s;
252	for (n = 0; *t++; n++)
253		;
254	return (n);
255}
256
257/*
258 * scomp(x,y) - return -1 if x < y,
259 *		0 if x == y,
260 *		return 1 if x > y, all lexicographically
261 */
262int
263scomp(CHR *x, CHR *y)
264{
265	CHR *a, *d;
266	a = (CHR *) x;
267	d = (CHR *) y;
268	while (*a || *d) {
269		if (*a > *d)
270			return (1);
271		if (*a < *d)
272			return (-1);
273		a++;
274		d++;
275	}
276	return (0);
277}
278
279int
280ctrans(CHR **ss)
281{
282	int c, k;
283	if ((c = **ss) != '\\')
284		return (c);
285	switch (c = *++*ss) {
286	case 'a':
287		c = '\a';
288		warning("\\a is ANSI C \"alert\" character");
289		break;
290	case 'v': c = '\v'; break;
291	case 'n': c = '\n'; break;
292	case 't': c = '\t'; break;
293	case 'r': c = '\r'; break;
294	case 'b': c = '\b'; break;
295	case 'f': c = 014; break;		/* form feed for ascii */
296	case '\\': c = '\\'; break;
297	case 'x': {
298		int dd;
299		warning("\\x is ANSI C hex escape");
300		if (digit((dd = *++*ss)) ||
301		    ('a' <= dd && dd <= 'f') ||
302		    ('A' <= dd && dd <= 'F')) {
303			c = 0;
304			while (digit(dd) ||
305			    ('A' <= dd && dd <= 'F') ||
306			    ('a' <= dd && dd <= 'f')) {
307				if (digit(dd))
308					c = c*16 + dd - '0';
309				else if (dd >= 'a')
310					c = c*16 + 10 + dd - 'a';
311				else
312					c = c*16 + 10 + dd - 'A';
313				dd = *++*ss;
314			}
315		} else
316			c = 'x';
317		break;
318		}
319	case '0': case '1': case '2': case '3':
320	case '4': case '5': case '6': case '7':
321		c -= '0';
322		while ((k = *(*ss+1)) >= '0' && k <= '7') {
323			c = c*8 + k - '0';
324			(*ss)++;
325		}
326		break;
327	}
328	return (c);
329}
330
331void
332cclinter(int sw)
333{
334	/* sw = 1 ==> ccl */
335	int i, j, k;
336	int m;
337	if (!sw) { /* is NCCL */
338		for (i = 1; i < ncg; i++)
339			symbol[i] ^= 1;	/* reverse value */
340	}
341	for (i = 1; i < ncg; i++)
342		if (symbol[i])
343			break;
344	if (i >= ncg)
345		return;
346	i = cindex[i];
347	/* see if ccl is already in our table */
348	j = 0;
349	if (i) {
350		for (j = 1; j < ncg; j++) {
351			if ((symbol[j] && cindex[j] != i) ||
352			    (!symbol[j] && cindex[j] == i))
353				break;
354		}
355	}
356	if (j >= ncg)
357		return;		/* already in */
358	m = 0;
359	k = 0;
360	for (i = 1; i < ncg; i++) {
361		if (symbol[i]) {
362			if (!cindex[i]) {
363				cindex[i] = ccount;
364				symbol[i] = 0;
365				m = 1;
366			} else
367				k = 1;
368		}
369	}
370	/* m == 1 implies last value of ccount has been used */
371	if (m)
372		ccount++;
373	if (k == 0)
374		return;	/* is now in as ccount wholly */
375	/* intersection must be computed */
376	for (i = 1; i < ncg; i++) {
377		if (symbol[i]) {
378			m = 0;
379			j = cindex[i];	/* will be non-zero */
380			for (k = 1; k < ncg; k++) {
381				if (cindex[k] == j) {
382					if (symbol[k])
383						symbol[k] = 0;
384					else {
385						cindex[k] = ccount;
386						m = 1;
387					}
388				}
389			}
390			if (m)
391				ccount++;
392		}
393	}
394}
395
396int
397usescape(int c)
398{
399	char d;
400	switch (c) {
401	case 'a':
402		c = '\a';
403		warning("\\a is ANSI C \"alert\" character"); break;
404	case 'v': c = '\v'; break;
405	case 'n': c = '\n'; break;
406	case 'r': c = '\r'; break;
407	case 't': c = '\t'; break;
408	case 'b': c = '\b'; break;
409	case 'f': c = 014; break;		/* form feed for ascii */
410	case 'x': {
411		int dd;
412		if (digit((dd = gch())) ||
413		    ('A' <= dd && dd <= 'F') ||
414		    ('a' <= dd && dd <= 'f')) {
415			c = 0;
416			while (digit(dd) ||
417			    ('A' <= dd && dd <= 'F') ||
418			    ('a' <= dd && dd <= 'f')) {
419				if (digit(dd))
420					c = c*16 + dd - '0';
421				else if (dd >= 'a')
422					c = c*16 + 10 + dd - 'a';
423				else
424					c = c*16 + 10 + dd - 'A';
425				if (!digit(peek) &&
426				    !('A' <= peek && peek <= 'F') &&
427				    !('a' <= peek && peek <= 'f'))
428					break;
429				dd = gch();
430			}
431
432		} else
433			c = 'x';
434		break;
435	}
436	case '0': case '1': case '2': case '3':
437	case '4': case '5': case '6': case '7':
438		c -= '0';
439		while ('0' <= (d = gch()) && d <= '7') {
440			c = c * 8 + (d-'0');
441			if (!('0' <= peek && peek <= '7')) break;
442			}
443
444		break;
445	}
446
447	if (handleeuc && !isascii(c)) {
448		char tmpchar = c & 0x00ff;
449		(void) mbtowc((wchar_t *)&c, &tmpchar, sizeof (tmpchar));
450	}
451	return (c);
452}
453
454int
455lookup(CHR *s, CHR **t)
456{
457	int i;
458	i = 0;
459	while (*t) {
460		if (scomp(s, *t) == 0)
461			return (i);
462		i++;
463		t++;
464	}
465	return (-1);
466}
467
468void
469cpycom(CHR *p)
470{
471	static CHR *t;
472	static int c;
473	t = p;
474
475	if (sargv[optind] == NULL)
476		(void) fprintf(fout, "\n# line %d\n", yyline);
477	else
478		(void) fprintf(fout,
479		    "\n# line %d \"%s\"\n", yyline, sargv[optind]);
480
481	(void) putc(*t++, fout);
482	(void) putc(*t++, fout);
483	while (*t) {
484		while (*t == '*') {
485			(void) putc(*t++, fout);
486			if (*t == '/')
487				goto backcall;
488		}
489		/*
490		 * FIX BUG #1058428, not parsing comments correctly
491		 * that span more than one line
492		 */
493		if (*t != NULL)
494			(void) putc(*t++, fout);
495	}
496	(void) putc('\n', fout);
497	while (c = gch()) {
498		while (c == '*') {
499			(void) putc((char)c, fout);
500			if ((c = gch()) == '/') {
501				while ((c = gch()) == ' ' || c == '\t')
502					;
503				if (!space(c))
504					error("unacceptable statement");
505				prev = '\n';
506				goto backcall;
507			}
508		}
509		(void) putc((char)c, fout);
510	}
511	error("unexpected EOF inside comment");
512backcall:
513	(void) putc('/', fout);
514	(void) putc('\n', fout);
515}
516
517/*
518 * copy C action to the next ; or closing
519 */
520int
521cpyact(void)
522{
523	int brac, c, mth;
524	static int sw, savline;
525
526	brac = 0;
527	sw = TRUE;
528	savline = yyline;
529
530	if (sargv[optind] == NULL)
531		(void) fprintf(fout, "\n# line %d\n", yyline);
532	else
533		(void) fprintf(fout,
534		    "\n# line %d \"%s\"\n", yyline, sargv[optind]);
535
536	while (!eof) {
537		c = gch();
538	swt:
539		switch (c) {
540		case '|':
541			if (brac == 0 && sw == TRUE) {
542				if (peek == '|')
543					(void) gch(); /* eat up an extra '|' */
544				return (0);
545			}
546			break;
547		case ';':
548			if (brac == 0) {
549				(void) putwc(c, fout);
550				(void) putc('\n', fout);
551				return (1);
552			}
553			break;
554		case '{':
555			brac++;
556			savline = yyline;
557			break;
558		case '}':
559			brac--;
560			if (brac == 0) {
561				(void) putwc(c, fout);
562				(void) putc('\n', fout);
563				return (1);
564			}
565			break;
566		case '/':
567			(void) putwc(c, fout);
568			c = gch();
569			if (c != '*')
570				goto swt;
571			(void) putwc(c, fout);
572			savline = yyline;
573			while (c = gch()) {
574				while (c == '*') {
575					(void) putwc(c, fout);
576					if ((c = gch()) == '/') {
577						(void) putc('/', fout);
578						while ((c = gch()) == ' ' ||
579						    c == '\t' || c == '\n')
580							(void) putwc(c, fout);
581						goto swt;
582					}
583				}
584				(void) putc((char)c, fout);
585			}
586			yyline = savline;
587			error("EOF inside comment");
588			/* NOTREACHED */
589			break;
590		case '\'': /* character constant */
591		case '"': /* character string */
592			mth = c;
593			(void) putwc(c, fout);
594			while (c = gch()) {
595				if (c == '\\') {
596					(void) putwc(c, fout);
597					c = gch();
598				}
599				else
600					if (c == mth)
601						goto loop;
602				(void) putwc(c, fout);
603				if (c == '\n') {
604					yyline--;
605					error(
606"Non-terminated string or character constant");
607				}
608			}
609			error("EOF in string or character constant");
610			/* NOTREACHED */
611			break;
612		case '\0':
613			yyline = savline;
614			error("Action does not terminate");
615			/* NOTREACHED */
616			break;
617		default:
618			break; /* usual character */
619		}
620	loop:
621		if (c != ' ' && c != '\t' && c != '\n')
622			sw = FALSE;
623		(void) putwc(c, fout);
624		if (peek == '\n' && !brac && copy_line) {
625			(void) putc('\n', fout);
626			return (1);
627		}
628	}
629	error("Premature EOF");
630	return (0);
631}
632
633int
634gch(void)
635{
636	int c;
637	prev = pres;
638	c = pres = peek;
639	peek = pushptr > pushc ? *--pushptr : getwc(fin);
640	while (peek == EOF) {
641		if (no_input) {
642			if (!yyline)
643				error("Cannot read from -- %s",
644				    sargv[optind]);
645			if (optind < sargc-1) {
646				yyline = 0;
647				if (fin != stdin)
648					(void) fclose(fin);
649				fin = fopen(sargv[++optind], "r");
650				if (fin == NULL)
651					error("Cannot open file -- %s",
652					    sargv[optind]);
653				peek = getwc(fin);
654			} else
655				break;
656		} else {
657			if (fin != stdin)
658				(void) fclose(fin);
659			if (!yyline)
660				error("Cannot read from -- standard input");
661			else
662				break;
663		}
664	}
665	if (c == EOF) {
666		eof = TRUE;
667		return (0);
668	}
669	if (c == '\n')
670		yyline++;
671	return (c);
672}
673
674int
675mn2(int a, int d, int c)
676{
677	if (tptr >= treesize) {
678		tptr++;
679		error("Parse tree too big %s",
680		    (treesize == TREESIZE ? "\nTry using %e num" : ""));
681	}
682	if (d >= treesize) {
683		error("Parse error");
684	}
685	name[tptr] = a;
686	left[tptr] = d;
687	right[tptr] = c;
688	parent[tptr] = 0;
689	nullstr[tptr] = 0;
690	switch (a) {
691	case RSTR:
692		parent[d] = tptr;
693		break;
694	case BAR:
695	case RNEWE:
696		if (nullstr[d] || nullstr[c])
697			nullstr[tptr] = TRUE;
698		parent[d] = parent[c] = tptr;
699		break;
700	case RCAT:
701	case DIV:
702		if (nullstr[d] && nullstr[c])
703			nullstr[tptr] = TRUE;
704		parent[d] = parent[c] = tptr;
705		break;
706	/* XCU4: add RXSCON */
707	case RXSCON:
708	case RSCON:
709		parent[d] = tptr;
710		nullstr[tptr] = nullstr[d];
711		break;
712#ifdef DEBUG
713	default:
714		warning("bad switch mn2 %d %d", a, d);
715		break;
716#endif
717	}
718	return (tptr++);
719}
720
721int
722mn1(int a, int d)
723{
724	if (tptr >= treesize) {
725		tptr++;
726		error("Parse tree too big %s",
727		    (treesize == TREESIZE ? "\nTry using %e num" : ""));
728	}
729	name[tptr] = a;
730	left[tptr] = d;
731	parent[tptr] = 0;
732	nullstr[tptr] = 0;
733	switch (a) {
734	case RCCL:
735	case RNCCL:
736		if (slength((CHR *)d) == 0)
737			nullstr[tptr] = TRUE;
738		break;
739	case STAR:
740	case QUEST:
741		nullstr[tptr] = TRUE;
742		parent[d] = tptr;
743		break;
744	case PLUS:
745	case CARAT:
746		nullstr[tptr] = nullstr[d];
747		parent[d] = tptr;
748		break;
749	case S2FINAL:
750		nullstr[tptr] = TRUE;
751		break;
752#ifdef DEBUG
753	case FINAL:
754	case S1FINAL:
755		break;
756	default:
757		warning("bad switch mn1 %d %d", a, d);
758		break;
759#endif
760	}
761	return (tptr++);
762}
763
764int
765mn0(int a)
766{
767	if (tptr >= treesize) {
768		tptr++;
769		error("Parse tree too big %s",
770		    (treesize == TREESIZE ? "\nTry using %e num" : ""));
771	}
772
773	name[tptr] = a;
774	parent[tptr] = 0;
775	nullstr[tptr] = 0;
776	if (ISOPERATOR(a)) {
777		switch (a) {
778		case DOT: break;
779		case RNULLS: nullstr[tptr] = TRUE; break;
780#ifdef DEBUG
781		default:
782			warning("bad switch mn0 %d", a);
783			break;
784#endif
785		}
786	}
787	return (tptr++);
788}
789
790void
791munput(int t, CHR *p)
792{
793	int i, j;
794	if (t == 'c') {
795		*pushptr++ = peek;
796		peek = *p;
797	} else if (t == 's') {
798		*pushptr++ = peek;
799		peek = p[0];
800		i = slength(p);
801		for (j = i - 1; j >= 1; j--)
802			*pushptr++ = p[j];
803	}
804	if (pushptr >= pushc + TOKENSIZE)
805		error("Too many characters pushed");
806}
807
808int
809dupl(int n)
810{
811	/* duplicate the subtree whose root is n, return ptr to it */
812	int i;
813	i = name[n];
814	if (!ISOPERATOR(i))
815		return (mn0(i));
816	switch (i) {
817	case DOT:
818	case RNULLS:
819		return (mn0(i));
820	case RCCL: case RNCCL: case FINAL: case S1FINAL: case S2FINAL:
821		return (mn1(i, left[n]));
822	case STAR: case QUEST: case PLUS: case CARAT:
823		return (mn1(i, dupl(left[n])));
824
825	/* XCU4: add RXSCON */
826	case RSTR: case RSCON: case RXSCON:
827		return (mn2(i, dupl(left[n]), right[n]));
828	case BAR: case RNEWE: case RCAT: case DIV:
829		return (mn2(i, dupl(left[n]), dupl(right[n])));
830	}
831	return (0);
832}
833
834#ifdef DEBUG
835void
836allprint(CHR c)
837{
838	switch (c) {
839	case 014:
840		(void) printf("\\f");
841		charc++;
842		break;
843	case '\n':
844		(void) printf("\\n");
845		charc++;
846		break;
847	case '\t':
848		(void) printf("\\t");
849		charc++;
850		break;
851	case '\b':
852		(void) printf("\\b");
853		charc++;
854		break;
855	case ' ':
856		(void) printf("\\_");
857		break;
858	default:
859		if (!iswprint(c)) {
860			printf("\\x%-2x", c); /* up to fashion. */
861			charc += 3;
862		} else
863			(void) putwc(c, stdout);
864		break;
865	}
866	charc++;
867}
868
869void
870strpt(CHR *s)
871{
872	charc = 0;
873	while (*s) {
874		allprint(*s++);
875		if (charc > LINESIZE) {
876			charc = 0;
877			(void) printf("\n\t");
878		}
879	}
880}
881
882void
883sect1dump(void)
884{
885	int i;
886	(void) printf("Sect 1:\n");
887	if (def[0]) {
888		(void) printf("str	trans\n");
889		i = -1;
890		while (def[++i])
891			(void) printf("%ws\t%ws\n", def[i], subs[i]);
892	}
893	if (sname[0]) {
894		(void) printf("start names\n");
895		i = -1;
896		while (sname[++i])
897			(void) printf("%ws\n", sname[i]);
898	}
899	if (chset == TRUE) {
900		(void) printf("char set changed\n");
901		for (i = 1; i < NCH; i++) {
902			if (i != ctable[i]) {
903				allprint(i);
904				(void) putchar(' ');
905				iswprint(ctable[i]) ?
906				    (void) putwc(ctable[i], stdout) :
907				    (void) printf("%d", ctable[i]);
908				(void) putchar('\n');
909			}
910		}
911	}
912}
913
914void
915sect2dump(void)
916{
917	(void) printf("Sect 2:\n");
918	treedump();
919}
920
921void
922treedump(void)
923{
924	int t;
925	CHR *p;
926	(void) printf("treedump %d nodes:\n", tptr);
927	for (t = 0; t < tptr; t++) {
928		(void) printf("%4d ", t);
929		parent[t] ? (void) printf("p=%4d", parent[t]) :
930		    (void) printf("      ");
931		(void) printf("  ");
932		if (!ISOPERATOR(name[t])) {
933			allprint(name[t]);
934		} else
935			switch (name[t]) {
936			case RSTR:
937				(void) printf("%d ", left[t]);
938				allprint(right[t]);
939				break;
940			case RCCL:
941				(void) printf("ccl ");
942				strpt(left[t]);
943				break;
944			case RNCCL:
945				(void) printf("nccl ");
946				strpt(left[t]);
947				break;
948			case DIV:
949				(void) printf("/ %d %d", left[t], right[t]);
950				break;
951			case BAR:
952				(void) printf("| %d %d", left[t], right[t]);
953				break;
954			case RCAT:
955				(void) printf("cat %d %d", left[t], right[t]);
956				break;
957			case PLUS:
958				(void) printf("+ %d", left[t]);
959				break;
960			case STAR:
961				(void) printf("* %d", left[t]);
962				break;
963			case CARAT:
964				(void) printf("^ %d", left[t]);
965				break;
966			case QUEST:
967				(void) printf("? %d", left[t]);
968				break;
969			case RNULLS:
970				(void) printf("nullstring");
971				break;
972			case FINAL:
973				(void) printf("final %d", left[t]);
974				break;
975			case S1FINAL:
976				(void) printf("s1final %d", left[t]);
977				break;
978			case S2FINAL:
979				(void) printf("s2final %d", left[t]);
980				break;
981			case RNEWE:
982				(void) printf("new %d %d", left[t], right[t]);
983				break;
984
985			/* XCU4: add RXSCON */
986			case RXSCON:
987				p = (CHR *)right[t];
988				(void) printf("exstart %s", sname[*p++-1]);
989				while (*p)
990					(void) printf(", %ws", sname[*p++-1]);
991				(void) printf(" %d", left[t]);
992				break;
993			case RSCON:
994				p = (CHR *)right[t];
995				(void) printf("start %s", sname[*p++-1]);
996				while (*p)
997					(void) printf(", %ws", sname[*p++-1]);
998				(void) printf(" %d", left[t]);
999				break;
1000			case DOT:
1001				printf("dot");
1002				break;
1003			default:
1004				(void) printf(
1005				"unknown %d %d %d", name[t], left[t], right[t]);
1006				break;
1007			}
1008		if (nullstr[t])
1009			(void) printf("\t(null poss.)");
1010		(void) putchar('\n');
1011	}
1012}
1013#endif
1014