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 "dextern.h"
32#include "sgs.h"
33#include <stdio.h>
34
35#define	IDENTIFIER 257
36
37#define	MARK 258
38#define	TERM 259
39#define	LEFT 260
40#define	RIGHT 261
41#define	BINARY 262
42#define	PREC 263
43#define	LCURLY 264
44#define	C_IDENTIFIER 265  /* name followed by colon */
45#define	NUMBER 266
46#define	START 267
47#define	TYPEDEF 268
48#define	TYPENAME 269
49#define	UNION 270
50#define	ENDFILE 0
51#define	LHS_TEXT_LEN		80	/* length of lhstext */
52#define	RHS_TEXT_LEN		640	/* length of rhstext */
53	/* communication variables between various I/O routines */
54
55#define	v_FLAG	0x01
56#define	d_FLAG	0x02
57#define	DEFAULT_PREFIX	"y"
58
59char *infile;				/* input file name 		*/
60static int numbval;			/* value of an input number 	*/
61static int toksize = NAMESIZE;
62static wchar_t *tokname;	/* input token name		*/
63char *parser = PARSER;		/* location of common parser 	*/
64
65static void finact(void);
66static wchar_t *cstash(wchar_t *);
67static void defout(void);
68static void cpyunion(void);
69static void cpycode(void);
70static void cpyact(int);
71static void lhsfill(wchar_t *);
72static void rhsfill(wchar_t *);
73static void lrprnt(void);
74static void beg_debug(void);
75static void end_toks(void);
76static void end_debug(void);
77static void exp_tokname(void);
78static void exp_prod(void);
79static void exp_ntok(void);
80static void exp_nonterm(void);
81static int defin(int, wchar_t *);
82static int gettok(void);
83static int chfind(int, wchar_t *);
84static int skipcom(void);
85static int findchtok(int);
86static void put_prefix_define(char *);
87
88
89/* storage of names */
90
91/*
92 * initial block to place token and
93 * nonterminal names are stored
94 * points to initial block - more space
95 * is allocated as needed.
96 */
97static wchar_t cnamesblk0[CNAMSZ];
98static wchar_t *cnames = cnamesblk0;
99
100/* place where next name is to be put in */
101static wchar_t *cnamp = cnamesblk0;
102
103/* number of defined symbols output */
104static int ndefout = 3;
105
106	/* storage of types */
107static int defunion = 0;	/* union of types defined? */
108static int ntypes = 0;		/* number of types defined */
109static wchar_t *typeset[NTYPES]; /* pointers to type tags */
110
111	/* symbol tables for tokens and nonterminals */
112
113int ntokens = 0;
114int ntoksz = NTERMS;
115TOKSYMB *tokset;
116int *toklev;
117
118int nnonter = -1;
119NTSYMB *nontrst;
120int nnontersz = NNONTERM;
121
122static int start;	/* start symbol */
123
124	/* assigned token type values */
125static int extval = 0;
126
127	/* input and output file descriptors */
128
129FILE *finput;		/* yacc input file */
130FILE *faction;		/* file for saving actions */
131FILE *fdefine;		/* file for # defines */
132FILE *ftable;		/* y.tab.c file */
133FILE *ftemp;		/* tempfile to pass 2 */
134FILE *fdebug;		/* where the strings for debugging are stored */
135FILE *foutput;		/* y.output file */
136
137	/* output string */
138
139static wchar_t *lhstext;
140static wchar_t *rhstext;
141
142	/* storage for grammar rules */
143
144int *mem0; /* production storage */
145int *mem;
146int *tracemem;
147extern int *optimmem;
148int new_memsize = MEMSIZE;
149int nprod = 1;	/* number of productions */
150int nprodsz = NPROD;
151
152int **prdptr;
153int *levprd;
154wchar_t *had_act;
155
156/* flag for generating the # line's default is yes */
157int gen_lines = 1;
158int act_lines = 0;
159
160/* flag for whether to include runtime debugging */
161static int gen_testing = 0;
162
163/* flag for version stamping--default turned off */
164static char *v_stmp = "n";
165
166int nmbchars = 0;	/* number of mb literals in mbchars */
167MBCLIT *mbchars = (MBCLIT *) 0; /* array of mb literals */
168int nmbcharsz = 0; /* allocated space for mbchars */
169
170void
171setup(argc, argv)
172int argc;
173char *argv[];
174{	int ii, i, j, lev, t, ty;
175		/* ty is the sequencial number of token name in tokset */
176	int c;
177	int *p;
178	char *cp;
179	wchar_t actname[8];
180	unsigned int options = 0;
181	char *file_prefix = DEFAULT_PREFIX;
182	char *sym_prefix = "";
183#define	F_NAME_LENGTH	128
184	char	fname[F_NAME_LENGTH+1];
185
186	foutput = NULL;
187	fdefine = NULL;
188	i = 1;
189
190	tokname = (wchar_t *)malloc(sizeof (wchar_t) * toksize);
191	tokset = (TOKSYMB *)malloc(sizeof (TOKSYMB) * ntoksz);
192	toklev = (int *)malloc(sizeof (int) * ntoksz);
193	nontrst = (NTSYMB *)malloc(sizeof (NTSYMB) * nnontersz);
194	mem0 = (int *)malloc(sizeof (int) * new_memsize);
195	prdptr = (int **)malloc(sizeof (int *) * (nprodsz+2));
196	levprd = (int *)malloc(sizeof (int) * (nprodsz+2));
197	had_act = (wchar_t *)calloc((nprodsz + 2), sizeof (wchar_t));
198	lhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * LHS_TEXT_LEN);
199	rhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * RHS_TEXT_LEN);
200	aryfil(toklev, ntoksz, 0);
201	aryfil(levprd, nprodsz, 0);
202	for (ii = 0; ii < ntoksz; ++ii)
203		tokset[ii].value = 0;
204	for (ii = 0; ii < nnontersz; ++ii)
205		nontrst[ii].tvalue = 0;
206	aryfil(mem0, new_memsize, 0);
207	mem = mem0;
208	tracemem = mem0;
209
210	while ((c = getopt(argc, argv, "vVdltp:Q:Y:P:b:")) != EOF)
211		switch (c) {
212		case 'v':
213			options |= v_FLAG;
214			break;
215		case 'V':
216			(void) fprintf(stderr, "yacc: %s %s\n",
217			    (const char *)SGU_PKG,
218			    (const char *)SGU_REL);
219			break;
220		case 'Q':
221			v_stmp = optarg;
222			if (*v_stmp != 'y' && *v_stmp != 'n')
223/*
224 * TRANSLATION_NOTE  -- This is a message from yacc.
225 *	This message is passed to error() function.
226 *	Do not translate -Q and [y/n].
227 */
228				error(gettext(
229			"yacc: -Q should be followed by [y/n]"));
230			break;
231		case 'd':
232			options |= d_FLAG;
233			break;
234		case 'l':
235			gen_lines = 0;	/* don't gen #lines */
236			break;
237		case 't':
238			gen_testing = 1;	/* set YYDEBUG on */
239			break;
240		case 'Y':
241			cp = (char *)malloc(strlen(optarg)+
242				sizeof ("/yaccpar") + 1);
243			cp = strcpy(cp, optarg);
244			parser = strcat(cp, "/yaccpar");
245			break;
246		case 'P':
247			parser = optarg;
248			break;
249		case 'p':
250			if (strcmp(optarg, "yy") != 0)
251				sym_prefix = optarg;
252			else
253				sym_prefix = "";
254			break;
255		case 'b':
256			file_prefix = optarg;
257			break;
258		case '?':
259		default:
260/*
261 * TRANSLATION_NOTE  -- This is a message from yacc.
262 *	This message is passed to error() function.
263 *	This is a usage message. The translate should be
264 *	consistent with man page translation.
265 */
266			(void) fprintf(stderr, gettext(
267"Usage: yacc [-vVdltY] [-Q(y/n)] [-b file_prefix] [-p sym_prefix]"
268" [-P parser] file\n"));
269			exit(1);
270		}
271	/*
272	 * Open y.output if -v is specified
273	 */
274	if (options & v_FLAG) {
275		(void) strncpy(fname,
276			file_prefix,
277			F_NAME_LENGTH-strlen(".output"));
278		(void) strcat(fname, ".output");
279		foutput = fopen(fname, "w");
280		if (foutput == NULL)
281			error(gettext(
282			"cannot open y.output"));
283	}
284
285	/*
286	 * Open y.tab.h if -d is specified
287	 */
288	if (options & d_FLAG) {
289		(void) strncpy(fname,
290			file_prefix,
291			F_NAME_LENGTH-strlen(".tab.h"));
292		(void) strcat(fname, ".tab.h");
293		fdefine = fopen(fname, "w");
294		if (fdefine == NULL)
295			error(gettext(
296			"cannot open y.tab.h"));
297	}
298
299	fdebug = fopen(DEBUGNAME, "w");
300	if (fdebug == NULL)
301/*
302 * TRANSLATION_NOTE  -- This is a message from yacc.
303 *	This message is passed to error() function.
304 *	Do not translate yacc.debug.
305 */
306		error(gettext(
307		"cannot open yacc.debug"));
308	/*
309	 * Open y.tab.c
310	 */
311	(void) strncpy(fname,
312		file_prefix,
313		F_NAME_LENGTH-strlen(".tab.c"));
314	(void) strcat(fname, ".tab.c");
315	ftable = fopen(fname, "w");
316	if (ftable == NULL)
317		error(gettext(
318		"cannot open %s"), fname);
319
320	ftemp = fopen(TEMPNAME, "w");
321	faction = fopen(ACTNAME, "w");
322	if (ftemp == NULL || faction == NULL)
323/*
324 * TRANSLATION_NOTE  -- This is a message from yacc.
325 *	This message is passed to error() function.
326 *	The message means: "Could not open a temporary file."
327 */
328		error(gettext(
329		"cannot open temp file"));
330
331	if ((finput = fopen(infile = argv[optind], "r")) == NULL)
332/*
333 * TRANSLATION_NOTE  -- This is a message from yacc.
334 *	This message is passed to error() function.
335 */
336		error(gettext(
337		"cannot open input file"));
338
339	lineno = 1;
340	cnamp = cnames;
341	(void) defin(0, L"$end");
342	extval = 0400;
343	(void) defin(0, L"error");
344	(void) defin(1, L"$accept");
345	mem = mem0;
346	lev = 0;
347	ty = 0;
348	i = 0;
349	beg_debug();	/* initialize fdebug file */
350
351	/*
352	 * sorry -- no yacc parser here.....
353	 *	we must bootstrap somehow...
354	 */
355
356	t = gettok();
357	if (*v_stmp == 'y')
358		(void) fprintf(ftable, "#ident\t\"yacc: %s %s\"\n",
359		    (const char *)SGU_PKG, (const char *)SGU_REL);
360	for (; t != MARK && t != ENDFILE; ) {
361		int tok_in_line;
362		switch (t) {
363
364		case L';':
365			t = gettok();
366			break;
367
368		case START:
369			if ((t = gettok()) != IDENTIFIER) {
370				error("bad %%start construction");
371				}
372			start = chfind(1, tokname);
373			t = gettok();
374			continue;
375
376		case TYPEDEF:
377			tok_in_line = 0;
378			if ((t = gettok()) != TYPENAME)
379/*
380 * TRANSLATION_NOTE  -- This is a message from yacc.
381 *	This message is passed to error() function.
382 *	Do not translate %%type.
383 */
384				error(gettext(
385				"bad syntax in %%type"));
386			ty = numbval;
387			for (;;) {
388				t = gettok();
389				switch (t) {
390
391				case IDENTIFIER:
392			/*
393			 * The following lines are idented to left.
394			 */
395			tok_in_line = 1;
396			if ((t = chfind(1, tokname)) < NTBASE) {
397				j = TYPE(toklev[t]);
398				if (j != 0 && j != ty) {
399/*
400 * TRANSLATION_NOTE  -- This is a message from yacc.
401 *	This message is passed to error() function.
402 */
403					error(gettext(
404					"type redeclaration of token %ws"),
405					tokset[t].name);
406					}
407				else
408					SETTYPE(toklev[t], ty);
409			} else {
410				j = nontrst[t-NTBASE].tvalue;
411				if (j != 0 && j != ty) {
412/*
413 * TRANSLATION_NOTE  -- This is a message from yacc.
414 *	This message is passed to error() function.
415 *	Check how nonterminal is translated in translated
416 *	yacc man page or yacc user's document.
417 */
418					error(gettext(
419				"type redeclaration of nonterminal %ws"),
420						nontrst[t-NTBASE].name);
421					}
422				else
423					nontrst[t-NTBASE].tvalue = ty;
424				}
425			/* FALLTHRU */
426			/*
427			 * End Indentation
428			 */
429				case L',':
430					continue;
431
432				case L';':
433					t = gettok();
434					break;
435				default:
436					break;
437					}
438				if (!tok_in_line)
439/*
440 * TRANSLATION_NOTE  -- This is a message from yacc.
441 *	This message is passed to error() function.
442 */
443					error(gettext(
444					"missing tokens or illegal tokens"));
445				break;
446				}
447			continue;
448
449		case UNION:
450			/* copy the union declaration to the output */
451			cpyunion();
452			defunion = 1;
453			t = gettok();
454			continue;
455
456		case LEFT:
457		case BINARY:
458		case RIGHT:
459			i++;
460			/* FALLTHRU */
461		case TERM:
462			tok_in_line = 0;
463
464			/* nonzero means new prec. and assoc. */
465			lev = (t-TERM) | 04;
466			ty = 0;
467
468			/* get identifiers so defined */
469
470			t = gettok();
471			if (t == TYPENAME) { /* there is a type defined */
472				ty = numbval;
473				t = gettok();
474				}
475
476			for (;;) {
477				switch (t) {
478
479				case L',':
480					t = gettok();
481					continue;
482
483				case L';':
484					break;
485
486				case IDENTIFIER:
487					tok_in_line = 1;
488					j = chfind(0, tokname);
489					if (j > NTBASE) {
490/*
491 * TRANSLATION_NOTE  -- This is a message from yacc.
492 *	This message is passed to error() function.
493 */
494						error(gettext(
495				"%ws is not a token."),
496						tokname);
497					}
498					if (lev & ~04) {
499						if (ASSOC(toklev[j]) & ~04)
500/*
501 * TRANSLATION_NOTE  -- This is a message from yacc.
502 *	This message is passed to error() function.
503 */
504							error(gettext(
505				"redeclaration of precedence of %ws"),
506						tokname);
507						SETASC(toklev[j], lev);
508						SETPLEV(toklev[j], i);
509					} else {
510						if (ASSOC(toklev[j]))
511						(void) warning(1, gettext(
512				"redeclaration of precedence of %ws."),
513							tokname);
514						SETASC(toklev[j], lev);
515						}
516					if (ty) {
517						if (TYPE(toklev[j]))
518							error(gettext(
519/*
520 * TRANSLATION_NOTE  -- This is a message from yacc.
521 *	This message is passed to error() function.
522 */
523						"redeclaration of type of %ws"),
524							tokname);
525						SETTYPE(toklev[j], ty);
526						}
527					if ((t = gettok()) == NUMBER) {
528						tokset[j].value = numbval;
529						if (j < ndefout && j > 2) {
530/*
531 * TRANSLATION_NOTE  -- This is a message from yacc.
532 *	This message is passed to error() function.
533 */
534							error(gettext(
535				"type number of %ws should be defined earlier"),
536							tokset[j].name);
537							}
538						if (numbval >= -YYFLAG1) {
539/*
540 * TRANSLATION_NOTE  -- This is a message from yacc.
541 *	This message is passed to error() function.
542 */
543							error(gettext(
544				"token numbers must be less than %d"),
545							-YYFLAG1);
546							}
547						t = gettok();
548						}
549					continue;
550
551					}
552				if (!tok_in_line)
553/*
554 * TRANSLATION_NOTE  -- This is a message from yacc.
555 *	This message is passed to error() function.
556 */
557					error(gettext(
558					"missing tokens or illegal tokens"));
559				break;
560				}
561			continue;
562
563		case LCURLY:
564			defout();
565			cpycode();
566			t = gettok();
567			continue;
568
569		default:
570			error("syntax error");
571
572			}
573
574		}
575
576	if (t == ENDFILE) {
577/*
578 * TRANSLATION_NOTE  -- This is a message from yacc.
579 *	This message is passed to error() function.
580 *	Do not translate %%%%.
581 */
582		error("unexpected EOF before %%%%");
583		}
584
585	/* t is MARK */
586
587	defout();
588	end_toks();	/* all tokens dumped - get ready for reductions */
589
590	(void) fprintf(ftable, "\n#include <inttypes.h>\n");
591	(void) fprintf(ftable, "\n#ifdef __STDC__\n");
592	(void) fprintf(ftable, "#include <stdlib.h>\n");
593	(void) fprintf(ftable, "#include <string.h>\n");
594	(void) fprintf(ftable, "#define	YYCONST	const\n");
595	(void) fprintf(ftable, "#else\n");
596	(void) fprintf(ftable, "#include <malloc.h>\n");
597	(void) fprintf(ftable, "#include <memory.h>\n");
598	(void) fprintf(ftable, "#define	YYCONST\n");
599	(void) fprintf(ftable, "#endif\n");
600	(void) fprintf(ftable, "\n#include <values.h>\n");
601
602	if (sym_prefix[0] != '\0')
603		put_prefix_define(sym_prefix);
604
605	(void) fprintf(ftable,
606	"\n#if defined(__cplusplus) || defined(__STDC__)\n");
607	(void) fprintf(ftable,
608	"\n#if defined(__cplusplus) && defined(__EXTERN_C__)\n");
609	(void) fprintf(ftable, "extern \"C\" {\n");
610	(void) fprintf(ftable, "#endif\n");
611	(void) fprintf(ftable, "#ifndef yyerror\n");
612	(void) fprintf(ftable, "#if defined(__cplusplus)\n");
613	(void) fprintf(ftable, "	void yyerror(YYCONST char *);\n");
614	(void) fprintf(ftable, "#endif\n");
615	(void) fprintf(ftable, "#endif\n");
616	(void) fprintf(ftable, "#ifndef yylex\n");
617	(void) fprintf(ftable, "	int yylex(void);\n");
618	(void) fprintf(ftable, "#endif\n");
619	(void) fprintf(ftable, "	int yyparse(void);\n");
620	(void) fprintf(ftable,
621	"#if defined(__cplusplus) && defined(__EXTERN_C__)\n");
622	(void) fprintf(ftable, "}\n");
623	(void) fprintf(ftable, "#endif\n");
624	(void) fprintf(ftable, "\n#endif\n\n");
625
626	(void) fprintf(ftable, "#define yyclearin yychar = -1\n");
627	(void) fprintf(ftable, "#define yyerrok yyerrflag = 0\n");
628	(void) fprintf(ftable, "extern int yychar;\nextern int yyerrflag;\n");
629	if (!(defunion || ntypes))
630		(void) fprintf(ftable,
631			"#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
632	(void) fprintf(ftable, "YYSTYPE yylval;\n");
633	(void) fprintf(ftable, "YYSTYPE yyval;\n");
634	(void) fprintf(ftable, "typedef int yytabelem;\n");
635	(void) fprintf(ftable,
636		"#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n");
637	(void) fprintf(ftable, "#if YYMAXDEPTH > 0\n");
638	(void) fprintf(ftable, "int yy_yys[YYMAXDEPTH], *yys = yy_yys;\n");
639	(void) fprintf(ftable, "YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;\n");
640	(void) fprintf(ftable, "#else	/* user does initial allocation */\n");
641	(void) fprintf(ftable, "int *yys;\nYYSTYPE *yyv;\n#endif\n");
642	(void) fprintf(ftable, "static int yymaxdepth = YYMAXDEPTH;\n");
643
644	prdptr[0] = mem;
645	/* added production */
646	*mem++ = NTBASE;
647
648	/* if start is 0, we will overwrite with the lhs of the first rule */
649	*mem++ = start;
650	*mem++ = 1;
651	*mem++ = 0;
652	prdptr[1] = mem;
653
654	while ((t = gettok()) == LCURLY)
655		cpycode();
656
657	if (t != C_IDENTIFIER)
658		error("bad syntax on first rule");
659
660	if (!start)
661		prdptr[0][1] = chfind(1, tokname);
662
663	/* read rules */
664
665	while (t != MARK && t != ENDFILE) {
666
667		/* process a rule */
668
669		if (t == L'|') {
670			rhsfill((wchar_t *)0); /* restart fill of rhs */
671			*mem = *prdptr[nprod-1];
672			if (++mem >= &tracemem[new_memsize])
673				exp_mem(1);
674		} else if (t == C_IDENTIFIER) {
675			*mem = chfind(1, tokname);
676			if (*mem < NTBASE)
677/*
678 * TRANSLATION_NOTE  -- This is a message from yacc.
679 *	This message is passed to error() function.
680 *	Check how nonterminal is translated.
681 */
682				error(gettext(
683				"illegal nonterminal in grammar rule"));
684			if (++mem >= &tracemem[new_memsize])
685				exp_mem(1);
686			lhsfill(tokname);	/* new rule: restart strings */
687		} else
688/*
689 * TRANSLATION_NOTE  -- This is a message from yacc.
690 *	This message is passed to error() function.
691 */
692			error(gettext(
693			"illegal rule: missing semicolon or | ?"));
694
695		/* read rule body */
696
697
698		t = gettok();
699	more_rule:
700		while (t == IDENTIFIER) {
701			*mem = chfind(1, tokname);
702			if (*mem < NTBASE)
703				levprd[nprod] = toklev[*mem]& ~04;
704			if (++mem >= &tracemem[new_memsize])
705				exp_mem(1);
706			rhsfill(tokname);	/* add to rhs string */
707			t = gettok();
708			}
709
710		if (t == PREC) {
711			if (gettok() != IDENTIFIER)
712/*
713 * TRANSLATION_NOTE  -- This is a message from yacc.
714 *	This message is passed to error() function.
715 *	Do not translate %%prec.
716 */
717				error(gettext(
718				"illegal %%prec syntax"));
719			j = chfind(2, tokname);
720			if (j >= NTBASE)
721/*
722 * TRANSLATION_NOTE  -- This is a message from yacc.
723 *	This message is passed to error() function.
724 *	Do not translate %%prec.
725 */
726				error(gettext(
727				"nonterminal %ws illegal after %%prec"),
728				nontrst[j-NTBASE].name);
729			levprd[nprod] = toklev[j] & ~04;
730			t = gettok();
731			}
732
733		if (t == L'=') {
734			had_act[nprod] = 1;
735			levprd[nprod] |= ACTFLAG;
736			(void) fprintf(faction, "\ncase %d:", nprod);
737			cpyact(mem-prdptr[nprod] - 1);
738			(void) fprintf(faction, " break;");
739			if ((t = gettok()) == IDENTIFIER) {
740				/* action within rule... */
741
742				lrprnt();		/* dump lhs, rhs */
743				(void) wsprintf(actname, "$$%d", nprod);
744				/*
745				 * make it nonterminal
746				 */
747				j = chfind(1, actname);
748
749				/*
750				 * the current rule will become rule
751				 * number nprod+1 move the contents down,
752				 * and make room for the null
753				 */
754
755				if (mem + 2 >= &tracemem[new_memsize])
756					exp_mem(1);
757				for (p = mem; p >= prdptr[nprod]; --p)
758					p[2] = *p;
759				mem += 2;
760
761				/* enter null production for action */
762
763				p = prdptr[nprod];
764
765				*p++ = j;
766				*p++ = -nprod;
767
768				/* update the production information */
769
770				levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
771				levprd[nprod] = ACTFLAG;
772
773				if (++nprod >= nprodsz)
774					exp_prod();
775				prdptr[nprod] = p;
776
777				/*
778				 * make the action appear in
779				 * the original rule
780				 */
781				*mem++ = j;
782				if (mem >= &tracemem[new_memsize])
783					exp_mem(1);
784				/* get some more of the rule */
785				goto more_rule;
786			}
787		}
788		while (t == L';')
789			t = gettok();
790		*mem++ = -nprod;
791		if (mem >= &tracemem[new_memsize])
792			exp_mem(1);
793
794		/* check that default action is reasonable */
795
796		if (ntypes && !(levprd[nprod] & ACTFLAG) &&
797				nontrst[*prdptr[nprod]-NTBASE].tvalue) {
798			/* no explicit action, LHS has value */
799			int tempty;
800			tempty = prdptr[nprod][1];
801			if (tempty < 0)
802/*
803 * TRANSLATION_NOTE  -- This is a message from yacc.
804 *	This message is passed to error() function.
805 *	LHS means Left Hand Side. It does not need to be translated.
806 */
807				error(gettext(
808				"must return a value, since LHS has a type"));
809			else if (tempty >= NTBASE)
810				tempty = nontrst[tempty-NTBASE].tvalue;
811			else
812				tempty = TYPE(toklev[tempty]);
813			if (tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue) {
814/*
815 * TRANSLATION_NOTE  -- This is a message from yacc.
816 *	This message is passed to error() function.
817 *	Check how action is transltated in yacc man page or documents.
818 */
819				error(gettext(
820				"default action causes potential type clash"));
821			}
822		}
823
824		if (++nprod >= nprodsz)
825			exp_prod();
826		prdptr[nprod] = mem;
827		levprd[nprod] = 0;
828		}
829	/* end of all rules */
830
831	end_debug();		/* finish fdebug file's input */
832	finact();
833	if (t == MARK) {
834		if (gen_lines)
835			(void) fprintf(ftable, "\n# line %d \"%s\"\n",
836				lineno, infile);
837		while ((c = getwc(finput)) != EOF)
838			(void) putwc(c, ftable);
839		}
840	(void) fclose(finput);
841}
842
843static void
844finact()
845{
846	/* finish action routine */
847	(void) fclose(faction);
848	(void) fprintf(ftable, "# define YYERRCODE %d\n", tokset[2].value);
849}
850
851static wchar_t *
852cstash(s)
853register wchar_t *s;
854{
855	wchar_t *temp;
856	static int used = 0;
857	static int used_save = 0;
858	static int exp_cname = CNAMSZ;
859	int len = wslen(s);
860
861	/*
862	 * 2/29/88 -
863	 * Don't need to expand the table, just allocate new space.
864	 */
865	used_save = used;
866	while (len >= (exp_cname - used_save)) {
867		exp_cname += CNAMSZ;
868		if (!used)
869			free((char *)cnames);
870		if ((cnames = (wchar_t *)
871			malloc(sizeof (wchar_t)*exp_cname)) == NULL)
872/*
873 * TRANSLATION_NOTE  -- This is a message from yacc.
874 *	This message is passed to error() function.
875 *
876 *	You may just translate this as:
877 *	'Could not allocate internally used memory.'
878 */
879			error(gettext(
880			"cannot expand string dump"));
881		cnamp = cnames;
882		used = 0;
883	}
884
885	temp = cnamp;
886	do {
887		*cnamp++ = *s;
888	} while (*s++);
889	used += cnamp - temp;
890	return (temp);
891}
892
893static int
894defin(int t, wchar_t *s)
895{
896	/* define s to be a terminal if t=0 or a nonterminal if t=1 */
897
898	int val;
899
900	if (t) {
901		if (++nnonter >= nnontersz)
902			exp_nonterm();
903		nontrst[nnonter].name = cstash(s);
904		return (NTBASE + nnonter);
905		}
906	/* must be a token */
907	if (++ntokens >= ntoksz)
908		exp_ntok();
909	tokset[ntokens].name = cstash(s);
910
911	/* establish value for token */
912
913	if (s[0] == L' ' && s[2] == 0) { /* single character literal */
914		val = findchtok(s[1]);
915	} else if (s[0] == L' ' && s[1] == L'\\') { /* escape sequence */
916		if (s[3] == 0) { /* single character escape sequence */
917			switch (s[2]) {
918				/* character which is escaped */
919			case L'a':
920				(void) warning(1, gettext(
921/*
922 * TRANSLATION_NOTE  -- This is a message from yacc.
923 *	This message is passed to warning() function.
924 *	Do not trasnlate ANSI C, \\a.
925 */
926		"\\a is ANSI C \"alert\" character"));
927#if __STDC__ - 1 == 0
928				val = L'\a';
929				break;
930#else
931				val = L'\007';
932				break;
933#endif
934			case L'v': val = L'\v'; break;
935			case L'n': val = L'\n'; break;
936			case L'r': val = L'\r'; break;
937			case L'b': val = L'\b'; break;
938			case L't': val = L'\t'; break;
939			case L'f': val = L'\f'; break;
940			case L'\'': val = L'\''; break;
941			case L'"': val = L'"'; break;
942			case L'?': val = L'?'; break;
943			case L'\\': val = L'\\'; break;
944/*
945 * TRANSLATION_NOTE  -- This is a message from yacc.
946 *	This message is passed to error() function.
947 */
948			default: error(gettext(
949				"invalid escape"));
950			}
951		} else if (s[2] <= L'7' && s[2] >= L'0') { /* \nnn sequence */
952			int i = 3;
953			val = s[2] - L'0';
954			while (iswdigit(s[i]) && i <= 4) {
955				if (s[i] >= L'0' && s[i] <= L'7')
956					val = val * 8 + s[i] - L'0';
957				else
958/*
959 * TRANSLATION_NOTE  -- This is a message from yacc.
960 *	This message is passed to error() function.
961 */
962					error(gettext(
963					"illegal octal number"));
964				i++;
965			}
966			if (s[i] != 0)
967/*
968 * TRANSLATION_NOTE  -- This is a message from yacc.
969 *	This message is passed to error() function.
970 *	Do not translate \\nnn.
971 */
972				error(gettext(
973				"illegal \\nnn construction"));
974			if (val > 255)
975/*
976 * TRANSLATION_NOTE  -- This is a message from yacc.
977 *	This message is passed to error() function.
978 *	Do not translate
979 *		\\nnn, \\xnnnnnnnn.
980 */
981				error(
982"\\nnn exceed \\377; use \\xnnnnnnnn for wchar_t value of multibyte char");
983			if (val == 0 && i >= 4)
984/*
985 * TRANSLATION_NOTE  -- This is a message from yacc.
986 *	This message is passed to error() function.
987 *	Do not translate \\000.
988 */
989				error(gettext(
990				"'\\000' is illegal"));
991		} else if (s[2] == L'x') { /* hexadecimal \xnnn sequence */
992			int i = 3;
993			val = 0;
994/*
995 * TRANSLATION_NOTE  -- This is a message from yacc.
996 *	This message is passed to warning() function.
997 *	Do not translate \\x, ANSI C.
998 */
999			(void) warning(1, gettext(
1000			    "\\x is ANSI C hex escape"));
1001			if (iswxdigit(s[i]))
1002				while (iswxdigit(s[i])) {
1003					int tmpval;
1004					if (iswdigit(s[i]))
1005						tmpval = s[i] - L'0';
1006					else if (s[i] >= L'a')
1007						tmpval = s[i] - L'a' + 10;
1008					else
1009						tmpval = s[i] - L'A' + 10;
1010					val = 16 * val + tmpval;
1011					i++;
1012				}
1013			else
1014				error(gettext(
1015				"illegal hexadecimal number"));
1016			if (s[i] != 0)
1017/*
1018 * TRANSLATION_NOTE  -- This is a message from yacc.
1019 *	This message is passed to error() function.
1020 *	Do not translate \\xnn.
1021 */
1022				error(gettext(
1023				"illegal \\xnn construction"));
1024#define	LWCHAR_MAX	0x7fffffff
1025			if ((unsigned)val > LWCHAR_MAX)
1026/*
1027 * TRANSLATION_NOTE  -- This is a message from yacc.
1028 *	This message is passed to error() function.
1029 *	Do not translate \\xnnnnnnnn and %#x.
1030 */
1031				error(gettext(
1032				    " \\xnnnnnnnn exceed %#x"),
1033				    LWCHAR_MAX);
1034			if (val == 0)
1035/*
1036 * TRANSLATION_NOTE  -- This is a message from yacc.
1037 *	This message is passed to error() function.
1038 *	Do not translate \\x00.
1039 */
1040				error(gettext(
1041				"'\\x00' is illegal"));
1042			val = findchtok(val);
1043		} else
1044			error(gettext(
1045			"invalid escape"));
1046	} else {
1047		val = extval++;
1048	}
1049	tokset[ntokens].value = val;
1050	toklev[ntokens] = 0;
1051	return (ntokens);
1052}
1053
1054static void
1055defout()
1056{
1057	/* write out the defines (at the end of the declaration section) */
1058
1059	register int i, c;
1060	register wchar_t *cp;
1061
1062	for (i = ndefout; i <= ntokens; ++i) {
1063
1064		cp = tokset[i].name;
1065		if (*cp == L' ')	/* literals */
1066		{
1067			(void) fprintf(fdebug, WSFMT("\t\"%ws\",\t%d,\n"),
1068			    tokset[i].name + 1, tokset[i].value);
1069			continue;	/* was cp++ */
1070		}
1071
1072		for (; (c = *cp) != 0; ++cp) {
1073			if (iswlower(c) || iswupper(c) ||
1074			    iswdigit(c) || c == L'_')
1075				/* EMPTY */;
1076			else
1077				goto nodef;
1078		}
1079
1080		(void) fprintf(fdebug,
1081		    WSFMT("\t\"%ws\",\t%d,\n"), tokset[i].name,
1082		    tokset[i].value);
1083		(void) fprintf(ftable,
1084		    WSFMT("# define %ws %d\n"), tokset[i].name,
1085		    tokset[i].value);
1086		if (fdefine != NULL)
1087			(void) fprintf(fdefine,
1088			    WSFMT("# define %ws %d\n"),
1089			    tokset[i].name,
1090			    tokset[i].value);
1091
1092	nodef:;
1093	}
1094	ndefout = ntokens+1;
1095}
1096
1097static int
1098gettok()
1099{
1100	int i, base;
1101	static int peekline; /* number of '\n' seen in lookahead */
1102	int c, match, reserve;
1103begin:
1104	reserve = 0;
1105	lineno += peekline;
1106	peekline = 0;
1107	c = getwc(finput);
1108	/*
1109	 * while (c == ' ' || c == '\n' || c == '\t' || c == '\f') {
1110	 */
1111	while (iswspace(c)) {
1112		if (c == L'\n')
1113			++lineno;
1114		c = getwc(finput);
1115	}
1116	if (c == L'/') { /* skip comment */
1117		lineno += skipcom();
1118		goto begin;
1119	}
1120
1121	switch (c) {
1122
1123	case EOF:
1124		return (ENDFILE);
1125	case L'{':
1126		(void) ungetwc(c, finput);
1127		return (L'=');  /* action ... */
1128	case L'<':  /* get, and look up, a type name (union member name) */
1129		i = 0;
1130		while ((c = getwc(finput)) != L'>' &&
1131		    c != EOF && c != L'\n') {
1132			tokname[i] = c;
1133			if (++i >= toksize)
1134				exp_tokname();
1135			}
1136		if (c != L'>')
1137			error(gettext(
1138			"unterminated < ... > clause"));
1139		tokname[i] = 0;
1140		if (i == 0)
1141			error("missing type name in < ... > clause");
1142		for (i = 1; i <= ntypes; ++i) {
1143			if (!wscmp(typeset[i], tokname)) {
1144				numbval = i;
1145				return (TYPENAME);
1146				}
1147			}
1148		typeset[numbval = ++ntypes] = cstash(tokname);
1149		return (TYPENAME);
1150
1151	case L'"':
1152	case L'\'':
1153		match = c;
1154		tokname[0] = L' ';
1155		i = 1;
1156		for (;;) {
1157			c = getwc(finput);
1158			if (c == L'\n' || c == EOF)
1159				error(gettext(
1160				"illegal or missing ' or \""));
1161			if (c == L'\\') {
1162				c = getwc(finput);
1163				tokname[i] = L'\\';
1164				if (++i >= toksize)
1165					exp_tokname();
1166			} else if (c == match) break;
1167			tokname[i] = c;
1168			if (++i >= toksize)
1169				exp_tokname();
1170			}
1171		break;
1172
1173	case L'%':
1174	case L'\\':
1175
1176		switch (c = getwc(finput)) {
1177
1178		case L'0':	return (TERM);
1179		case L'<':	return (LEFT);
1180		case L'2':	return (BINARY);
1181		case L'>':	return (RIGHT);
1182		case L'%':
1183		case L'\\':	return (MARK);
1184		case L'=':	return (PREC);
1185		case L'{':	return (LCURLY);
1186		default:	reserve = 1;
1187			}
1188
1189	default:
1190
1191		if (iswdigit(c)) { /* number */
1192			numbval = c - L'0';
1193			base = (c == L'0') ? 8 : 10;
1194			for (c = getwc(finput);
1195			    iswdigit(c);
1196			    c = getwc(finput)) {
1197				numbval = numbval*base + c - L'0';
1198				}
1199			(void) ungetwc(c, finput);
1200			return (NUMBER);
1201		} else if (iswlower(c) || iswupper(c) ||
1202		    c == L'_' || c == L'.' ||
1203		    c == L'$') {
1204			i = 0;
1205			while (iswlower(c) || iswupper(c) ||
1206			    iswdigit(c) || c == L'_' ||
1207			    c == L'.' || c == L'$') {
1208				tokname[i] = c;
1209				if (reserve && iswupper(c))
1210					tokname[i] = towlower(c);
1211				if (++i >= toksize)
1212					exp_tokname();
1213				c = getwc(finput);
1214				}
1215			}
1216		else
1217			return (c);
1218
1219		(void) ungetwc(c, finput);
1220		}
1221
1222	tokname[i] = 0;
1223
1224	if (reserve) { /* find a reserved word */
1225		if (!wscmp(tokname, L"term"))
1226			return (TERM);
1227		if (!wscmp(tokname, L"token"))
1228			return (TERM);
1229		if (!wscmp(tokname, L"left"))
1230			return (LEFT);
1231		if (!wscmp(tokname, L"nonassoc"))
1232			return (BINARY);
1233		if (!wscmp(tokname, L"binary"))
1234			return (BINARY);
1235		if (!wscmp(tokname, L"right"))
1236			return (RIGHT);
1237		if (!wscmp(tokname, L"prec"))
1238			return (PREC);
1239		if (!wscmp(tokname, L"start"))
1240			return (START);
1241		if (!wscmp(tokname, L"type"))
1242			return (TYPEDEF);
1243		if (!wscmp(tokname, L"union"))
1244			return (UNION);
1245		error(gettext(
1246		    "invalid escape, or illegal reserved word: %ws"),
1247		    tokname);
1248		}
1249
1250	/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
1251
1252	c = getwc(finput);
1253	/*
1254	 * while (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '/')
1255	 * {
1256	 */
1257	while (iswspace(c) || c == L'/') {
1258		if (c == L'\n') {
1259			++peekline;
1260		} else if (c == L'/') { /* look for comments */
1261			peekline += skipcom();
1262			}
1263		c = getwc(finput);
1264		}
1265	if (c == L':')
1266		return (C_IDENTIFIER);
1267	(void) ungetwc(c, finput);
1268	return (IDENTIFIER);
1269}
1270
1271static int
1272fdtype(int t)
1273{
1274	/* determine the type of a symbol */
1275	int v;
1276	if (t >= NTBASE)
1277		v = nontrst[t-NTBASE].tvalue;
1278	else
1279		v = TYPE(toklev[t]);
1280	if (v <= 0)
1281		error(gettext(
1282		    "must specify type for %ws"),
1283		    (t >= NTBASE) ? nontrst[t-NTBASE].name:
1284		    tokset[t].name);
1285	return (v);
1286}
1287
1288static int
1289chfind(int t, wchar_t *s)
1290{
1291	int i;
1292
1293	if (s[0] == ' ')
1294		t = 0;
1295	TLOOP(i) {
1296		if (!wscmp(s, tokset[i].name)) {
1297			return (i);
1298		}
1299	}
1300	NTLOOP(i) {
1301		if (!wscmp(s, nontrst[i].name)) {
1302			return (i + NTBASE);
1303		}
1304	}
1305	/* cannot find name */
1306	if (t > 1)
1307		error(gettext(
1308		"%ws should have been defined earlier"), s);
1309	return (defin(t, s));
1310}
1311
1312static void
1313cpyunion()
1314{
1315	/*
1316	 * copy the union declaration to the output,
1317	 * and the define file if present
1318	 */
1319	int level, c;
1320	if (gen_lines)
1321		(void) fprintf(ftable, "\n# line %d \"%s\"\n", lineno, infile);
1322	(void) fprintf(ftable, "typedef union\n");
1323	if (fdefine)
1324		(void) fprintf(fdefine, "\ntypedef union\n");
1325	(void) fprintf(ftable, "#ifdef __cplusplus\n\tYYSTYPE\n#endif\n");
1326	if (fdefine)
1327		(void) fprintf(fdefine,
1328		    "#ifdef __cplusplus\n\tYYSTYPE\n#endif\n");
1329
1330	level = 0;
1331	for (;;) {
1332		if ((c = getwc(finput)) == EOF)
1333/*
1334 * TRANSLATION_NOTE  -- This is a message from yacc.
1335 *	This message is passed to error() function.
1336 *	EOF - End Of File.
1337 *	Do not translate %%union.
1338 */
1339			error(gettext(
1340			"EOF encountered while processing %%union"));
1341		(void) putwc(c, ftable);
1342		if (fdefine)
1343			(void) putwc(c, fdefine);
1344
1345		switch (c) {
1346
1347		case L'\n':
1348			++lineno;
1349			break;
1350
1351		case L'{':
1352			++level;
1353			break;
1354
1355		case L'}':
1356			--level;
1357			if (level == 0) { /* we are finished copying */
1358				(void) fprintf(ftable, " YYSTYPE;\n");
1359				if (fdefine)
1360					(void) fprintf(fdefine,
1361					" YYSTYPE;\nextern YYSTYPE yylval;\n");
1362				return;
1363				}
1364			}
1365		}
1366}
1367
1368static void
1369cpycode()
1370{
1371	/* copies code between \{ and \} */
1372
1373	int c;
1374	c = getwc(finput);
1375	if (c == L'\n') {
1376		c = getwc(finput);
1377		lineno++;
1378		}
1379	if (gen_lines)
1380		(void) fprintf(ftable, "\n# line %d \"%s\"\n", lineno, infile);
1381	while (c != EOF) {
1382		if (c == L'\\') {
1383			if ((c = getwc(finput)) == L'}')
1384				return;
1385			else
1386				(void) putwc(L'\\', ftable);
1387		} else if (c == L'%') {
1388			if ((c = getwc(finput)) == L'}')
1389				return;
1390			else
1391				(void) putwc(L'%', ftable);
1392		}
1393		(void) putwc(c, ftable);
1394		if (c == L'\n')
1395			++lineno;
1396		c = getwc(finput);
1397		}
1398/*
1399 * TRANSLATION_NOTE  -- This is a message from yacc.
1400 *	This message is passed to error() function.
1401 *	Do not translate %%}.
1402 */
1403	error(gettext(
1404	"eof before %%}"));
1405}
1406
1407static int
1408skipcom()
1409{
1410	/* skip over comments */
1411	int c, i = 0;  /* i is the number of lines skipped */
1412
1413	/* skipcom is called after reading a / */
1414
1415	if (getwc(finput) != L'*')
1416		error(gettext(
1417		"illegal comment"));
1418	c = getwc(finput);
1419	while (c != EOF) {
1420		while (c == L'*') {
1421			if ((c = getwc(finput)) == L'/')
1422				return (i);
1423			}
1424		if (c == L'\n')
1425			++i;
1426		c = getwc(finput);
1427		}
1428/*
1429 * TRANSLATION_NOTE  -- This is a message from yacc.
1430 *	This message is passed to error() function.
1431 *	EOF -- End Of File.
1432 */
1433	error(gettext(
1434	"EOF inside comment"));
1435	/* NOTREACHED */
1436	return (0);
1437}
1438
1439static void
1440cpyact(int offset)
1441{
1442	/* copy C action to the next ; or closing } */
1443	int brac, c, match, i, t, j, s, tok, argument, m;
1444	wchar_t id_name[NAMESIZE+1];
1445	int id_idx = 0;
1446
1447	if (gen_lines) {
1448		(void) fprintf(faction, "\n# line %d \"%s\"\n", lineno, infile);
1449		act_lines++;
1450	}
1451	brac = 0;
1452	id_name[0] = 0;
1453loop:
1454	c = getwc(finput);
1455swt:
1456	switch (c) {
1457	case L';':
1458		if (brac == 0) {
1459			(void) putwc(c, faction);
1460			return;
1461		}
1462		goto lcopy;
1463	case L'{':
1464		brac++;
1465		goto lcopy;
1466	case L'$':
1467		s = 1;
1468		tok = -1;
1469		argument = 1;
1470		while ((c = getwc(finput)) == L' ' || c == L'\t')
1471			/* NULL */;
1472		if (c == L'<') { /* type description */
1473			(void) ungetwc(c, finput);
1474			if (gettok() != TYPENAME)
1475/*
1476 * TRANSLATION_NOTE  -- This is a message from yacc.
1477 *	This message is passed to error() function.
1478 *	Do not translate $<ident>
1479 */
1480				error(gettext(
1481				"bad syntax on $<ident> clause"));
1482			tok = numbval;
1483			c = getwc(finput);
1484		}
1485		if (c == L'$') {
1486			(void) fprintf(faction, "yyval");
1487			if (ntypes) { /* put out the proper tag... */
1488				if (tok < 0)
1489					tok = fdtype(*prdptr[nprod]);
1490				(void) fprintf(faction,
1491				    WSFMT(".%ws"), typeset[tok]);
1492			}
1493			goto loop;
1494		}
1495		if (iswalpha(c)) {
1496			int same = 0;
1497			int id_sw = 0;
1498			(void) ungetwc(c, finput);
1499			if (gettok() != IDENTIFIER)
1500/*
1501 * TRANSLATION_NOTE  -- This is a message from yacc.
1502 *	This message is passed to error() function.
1503 *	Check how action is translated in yacc man page/document.
1504 */
1505				error(gettext(
1506				"bad action format"));
1507			/*
1508			 * Save the number of non-terminal
1509			 */
1510			id_sw = nnonter;
1511			t = chfind(1, tokname);
1512			/*
1513			 * Check if the identifier is added as a non-terminal
1514			 */
1515			if (id_sw != nnonter)
1516				id_sw = 1;
1517			else
1518				id_sw = 0;
1519			while ((c = getwc(finput)) == L' ' ||
1520			    c == L'\t')
1521				/* NULL */;
1522			if (c == L'#') {
1523				while ((c = getwc(finput)) == L' ' ||
1524				    c == L'\t')
1525					/* NULL */;
1526				if (iswdigit(c)) {
1527					m = 0;
1528					while (iswdigit(c)) {
1529						m = m*10+c-L'0';
1530						c = getwc(finput);
1531					}
1532					argument = m;
1533				} else
1534					error(gettext(
1535					"illegal character \"#\""));
1536			}
1537			if (argument < 1)
1538/*
1539 * TRANSLATION_NOTE  -- This is a message from yacc.
1540 *	This message is passed to error() function.
1541 *	Check how action is translated in yacc man page/document.
1542 */
1543				error(gettext(
1544				"illegal action argument no."));
1545			for (i = 1; i <= offset; ++i)
1546				if (prdptr[nprod][i] == t)
1547					if (++same == argument) {
1548						(void) fprintf(faction,
1549						    "yypvt[-%d]", offset-i);
1550						if (ntypes) {
1551							if (tok < 0)
1552								tok =
1553								/* CSTYLED */
1554								fdtype(prdptr[nprod][i]);
1555							(void) fprintf(faction,
1556							    WSFMT(".%ws"),
1557							    typeset[tok]);
1558						}
1559						goto swt;
1560					}
1561			/*
1562			 * This used to be handled as error.
1563			 * Treat this as a valid C statement.
1564			 * (Likely id with $ in.)
1565			 * If non-terminal is added, remove it from the list.
1566			 */
1567			(void) fprintf(faction, WSFMT("$%ws"), tokname);
1568/*
1569 * TRANSLATION_NOTE  -- This is a message from yacc.
1570 *	This message is passed to warning() function.
1571 *	Do not translate Ansi C.
1572 */
1573			warning(1, gettext(
1574	"Illegal character '$' in Ansi C symbol: %ws$%ws."),
1575			    id_name, tokname);
1576
1577			if (id_sw == 1)
1578				--nnonter;
1579			goto swt;
1580		}
1581		if (c == '-') {
1582			s = -s;
1583			c = getwc(finput);
1584		}
1585		if (iswdigit(c)) {
1586			j = 0;
1587			while (iswdigit(c)) {
1588				j = j*10 + c - L'0';
1589				c = getwc(finput);
1590			}
1591			j = j*s - offset;
1592			if (j > 0) {
1593/*
1594 * TRANSLATION_NOTE  -- This is a message from yacc.
1595 *	This message is passed to error() function.
1596 *	Do not translate $%d.
1597 */
1598				error(gettext(
1599				    "Illegal use of $%d"),
1600				    j + offset);
1601			}
1602			(void) fprintf(faction, "yypvt[-%d]", -j);
1603			if (ntypes) { /* put out the proper tag */
1604				if (j + offset <= 0 && tok < 0)
1605/*
1606 * TRANSLATION_NOTE  -- This is a message from yacc.
1607 *	This message is passed to error() function.
1608 *	Do not translate $%d.
1609 */
1610					error(gettext(
1611					    "must specify type of $%d"),
1612					    j + offset);
1613				if (tok < 0)
1614					tok = fdtype(prdptr[nprod][j+offset]);
1615				(void) fprintf(faction,
1616				    WSFMT(".%ws"), typeset[tok]);
1617			}
1618			goto swt;
1619		}
1620		(void) putwc(L'$', faction);
1621		if (s < 0)
1622			(void) putwc(L'-', faction);
1623		goto swt;
1624	case L'}':
1625		if (--brac)
1626			goto lcopy;
1627		(void) putwc(c, faction);
1628		return;
1629	case L'/':	/* look for comments */
1630		(void) putwc(c, faction);
1631		c = getwc(finput);
1632		if (c != L'*')
1633			goto swt;
1634		/* it really is a comment */
1635		(void) putwc(c, faction);
1636		c = getwc(finput);
1637		while (c != EOF) {
1638			while (c == L'*') {
1639				(void) putwc(c, faction);
1640				if ((c = getwc(finput)) == L'/')
1641					goto lcopy;
1642			}
1643			(void) putwc(c, faction);
1644			if (c == L'\n')
1645				++lineno;
1646			c = getwc(finput);
1647		}
1648		error("EOF inside comment");
1649		/* FALLTHRU */
1650	case L'\'':	/* character constant */
1651	case L'"':	/* character string */
1652		match = c;
1653		(void) putwc(c, faction);
1654		while ((c = getwc(finput)) != EOF) {
1655			if (c == L'\\') {
1656				(void) putwc(c, faction);
1657				c = getwc(finput);
1658				if (c == L'\n')
1659					++lineno;
1660			} else if (c == match)
1661				goto lcopy;
1662			else if (c == L'\n')
1663/*
1664 * TRANSLATION_NOTE  -- This is a message from yacc.
1665 *	This message is passed to error() function.
1666 *	This error message is issued when
1667 *	quoted string has multiple lines.
1668 */
1669				error(gettext(
1670				"newline in string or char. const."));
1671			(void) putwc(c, faction);
1672		}
1673		error(gettext(
1674		"EOF in string or character constant"));
1675		/* FALLTHRU */
1676	case EOF:
1677/*
1678 * TRANSLATION_NOTE  -- This is a message from yacc.
1679 *	This message is passed to error() function.
1680 *	Check how 'action' is translated in yacc mapage/document.
1681 */
1682		error(gettext(
1683		"action does not terminate"));
1684		/* FALLTHRU */
1685	case L'\n':
1686		++lineno;
1687		goto lcopy;
1688	}
1689lcopy:
1690	(void) putwc(c, faction);
1691	/*
1692	 * Save the possible identifier name.
1693	 * Used to print out a warning message.
1694	 */
1695	if (id_idx >= NAMESIZE) {
1696		/*
1697		 * Error. Silently ignore.
1698		 */
1699		/* EMPTY */;
1700	}
1701	/*
1702	 * If c has a possibility to be a
1703	 * part of identifier, save it.
1704	 */
1705	else if (iswalnum(c) || c == L'_') {
1706		id_name[id_idx++] = c;
1707		id_name[id_idx] = 0;
1708	} else {
1709		id_idx = 0;
1710		id_name[id_idx] = 0;
1711	}
1712	goto loop;
1713}
1714
1715static void
1716lhsfill(s)	/* new rule, dump old (if exists), restart strings */
1717wchar_t *s;
1718{
1719	static int lhs_len = LHS_TEXT_LEN;
1720	int s_lhs = wslen(s);
1721	if (s_lhs >= lhs_len) {
1722		lhs_len = s_lhs + 2;
1723		lhstext = (wchar_t *)
1724			realloc((char *)lhstext, sizeof (wchar_t)*lhs_len);
1725		if (lhstext == NULL)
1726/*
1727 * TRANSLATION_NOTE  -- This is a message from yacc.
1728 *	This message is passed to error() function.
1729 *	LHS -- Left Hand Side.
1730 */
1731			error(gettext(
1732			"couldn't expanded LHS length"));
1733	}
1734	rhsfill((wchar_t *)0);
1735	(void) wscpy(lhstext, s); /* don't worry about too long of a name */
1736}
1737
1738static void
1739rhsfill(s)
1740wchar_t *s;	/* either name or 0 */
1741{
1742	static wchar_t *loc;	/* next free location in rhstext */
1743	static int rhs_len = RHS_TEXT_LEN;
1744	static int used = 0;
1745	int s_rhs = (s == NULL ? 0 : wslen(s));
1746	register wchar_t *p;
1747
1748	if (!s)	/* print out and erase old text */
1749	{
1750		if (*lhstext)		/* there was an old rule - dump it */
1751			lrprnt();
1752		(loc = rhstext)[0] = 0;
1753		return;
1754	}
1755	/* add to stuff in rhstext */
1756	p = s;
1757
1758	used = loc - rhstext;
1759	if ((s_rhs + 3) >= (rhs_len - used)) {
1760		static wchar_t *textbase;
1761		textbase = rhstext;
1762		rhs_len += s_rhs + RHS_TEXT_LEN;
1763		rhstext = (wchar_t *)
1764			realloc((char *)rhstext, sizeof (wchar_t)*rhs_len);
1765		if (rhstext == NULL)
1766/*
1767 * TRANSLATION_NOTE  -- This is a message from yacc.
1768 *	This message is passed to error() function.
1769 *	RHS -- Right Hand Side.
1770 */
1771			error(gettext(
1772			"couldn't expanded RHS length"));
1773		loc = loc - textbase + rhstext;
1774	}
1775
1776	*loc++ = L' ';
1777	if (*s == L' ') /* special quoted symbol */
1778	{
1779		*loc++ = L'\'';	/* add first quote */
1780		p++;
1781	}
1782	while (*loc = *p++)
1783		if (loc++ > &rhstext[ RHS_TEXT_LEN ] - 3)
1784			break;
1785
1786	if (*s == L' ')
1787		*loc++ = L'\'';
1788	*loc = 0;		/* terminate the string */
1789}
1790
1791static void
1792lrprnt()	/* print out the left and right hand sides */
1793{
1794	wchar_t *rhs;
1795	wchar_t *m_rhs = NULL;
1796
1797	if (!*rhstext)		/* empty rhs - print usual comment */
1798		rhs = L" /* empty */";
1799	else {
1800		int idx1; /* tmp idx used to find if there are d_quotes */
1801		int idx2; /* tmp idx used to generate escaped string */
1802		wchar_t *p;
1803		/*
1804		 * Check if there are any double quote in RHS.
1805		 */
1806		for (idx1 = 0; rhstext[idx1] != 0; idx1++) {
1807			if (rhstext[idx1] == L'"') {
1808				/*
1809				 * A double quote is found.
1810				 */
1811				idx2 = wslen(rhstext)*2;
1812				p = m_rhs = (wchar_t *)
1813				    malloc((idx2 + 1)*sizeof (wchar_t));
1814				if (m_rhs == NULL)
1815/*
1816 * TRANSLATION_NOTE  -- This is a message from yacc.
1817 *	This message is passed to error() function.
1818 *	RHS - Right Hand Side.
1819 *
1820 *	You may just translate this as:
1821 *	'Could not allocate internally used memory.'
1822 */
1823					error(gettext(
1824					"Couldn't allocate memory for RHS."));
1825				/*
1826				 * Copy string
1827				 */
1828				for (idx2 = 0; rhstext[idx2] != 0; idx2++) {
1829					/*
1830					 * Check if this quote is escaped or not
1831					 */
1832					if (rhstext[idx2] == L'"') {
1833						int tmp_l = idx2-1;
1834						int cnt = 0;
1835						while (tmp_l >= 0 &&
1836						    rhstext[tmp_l] == '\\') {
1837							cnt++;
1838							tmp_l--;
1839						}
1840						/*
1841						 * If quote is not escaped,
1842						 * then escape it.
1843						 */
1844						if (cnt%2 == 0)
1845							*p++ = L'\\';
1846					}
1847					*p++ = rhstext[idx2];
1848				}
1849				*p = 0;
1850				/*
1851				 * Break from the loop
1852				 */
1853				break;
1854			}
1855		}
1856		if (m_rhs == NULL)
1857			rhs = rhstext;
1858		else
1859			rhs = m_rhs;
1860	}
1861	(void) fprintf(fdebug, WSFMT("\t\"%ws :%ws\",\n"), lhstext, rhs);
1862	if (m_rhs)
1863		free(m_rhs);
1864}
1865
1866
1867static void
1868beg_debug()	/* dump initial sequence for fdebug file */
1869{
1870	(void) fprintf(fdebug,
1871	    "typedef struct\n");
1872	(void) fprintf(fdebug,
1873	    "#ifdef __cplusplus\n\tyytoktype\n");
1874	(void) fprintf(fdebug, "#endif\n{\n");
1875	(void) fprintf(fdebug,
1876	    "#ifdef __cplusplus\nconst\n#endif\n");
1877	(void) fprintf(fdebug, "char *t_name; int t_val; } yytoktype;\n");
1878	(void) fprintf(fdebug,
1879	    "#ifndef YYDEBUG\n#\tdefine YYDEBUG\t%d", gen_testing);
1880	(void) fprintf(fdebug, "\t/*%sallow debugging */\n#endif\n\n",
1881	    gen_testing ? " " : " don't ");
1882	(void) fprintf(fdebug, "#if YYDEBUG\n\nyytoktype yytoks[] =\n{\n");
1883}
1884
1885
1886static void
1887end_toks()	/* finish yytoks array, get ready for yyred's strings */
1888{
1889	(void) fprintf(fdebug, "\t\"-unknown-\",\t-1\t/* ends search */\n");
1890	(void) fprintf(fdebug, "};\n\n");
1891	(void) fprintf(fdebug,
1892	    "#ifdef __cplusplus\nconst\n#endif\n");
1893	(void) fprintf(fdebug, "char * yyreds[] =\n{\n");
1894	(void) fprintf(fdebug, "\t\"-no such reduction-\",\n");
1895}
1896
1897
1898static void
1899end_debug()	/* finish yyred array, close file */
1900{
1901	lrprnt();		/* dump last lhs, rhs */
1902	(void) fprintf(fdebug, "};\n#endif /* YYDEBUG */\n");
1903	(void) fclose(fdebug);
1904}
1905
1906
1907/*
1908 * 2/29/88 -
1909 * The normal length for token sizes is NAMESIZE - If a token is
1910 * seen that has a longer length, expand "tokname" by NAMESIZE.
1911 */
1912static void
1913exp_tokname()
1914{
1915	toksize += NAMESIZE;
1916	tokname = (wchar_t *)
1917	    realloc((char *)tokname, sizeof (wchar_t) * toksize);
1918}
1919
1920
1921/*
1922 * 2/29/88 -
1923 *
1924 */
1925static void
1926exp_prod()
1927{
1928	int i;
1929	nprodsz += NPROD;
1930
1931	prdptr = (int **) realloc((char *)prdptr, sizeof (int *) * (nprodsz+2));
1932	levprd  = (int *)  realloc((char *)levprd, sizeof (int) * (nprodsz+2));
1933	had_act = (wchar_t *)
1934	    realloc((char *)had_act, sizeof (wchar_t) * (nprodsz+2));
1935	for (i = nprodsz-NPROD; i < nprodsz+2; ++i)
1936		had_act[i] = 0;
1937
1938	if ((*prdptr == NULL) || (levprd == NULL) || (had_act == NULL))
1939/*
1940 * TRANSLATION_NOTE  -- This is a message from yacc.
1941 *	This message is passed to error() function.
1942 *
1943 *	You may just translate this as:
1944 *	'Could not allocate internally used memory.'
1945 */
1946		error(gettext(
1947		"couldn't expand productions"));
1948}
1949
1950/*
1951 * 2/29/88 -
1952 * Expand the number of terminals.  Initially there are NTERMS;
1953 * each time space runs out, the size is increased by NTERMS.
1954 * The total size, however, cannot exceed MAXTERMS because of
1955 * the way LOOKSETS(struct looksets) is set up.
1956 * Tables affected:
1957 *	tokset, toklev : increased to ntoksz
1958 *
1959 *	tables with initial dimensions of TEMPSIZE must be changed if
1960 *	(ntoksz + NNONTERM) >= TEMPSIZE : temp1[]
1961 */
1962static void
1963exp_ntok()
1964{
1965	ntoksz += NTERMS;
1966
1967	tokset = (TOKSYMB *) realloc((char *)tokset, sizeof (TOKSYMB) * ntoksz);
1968	toklev = (int *) realloc((char *)toklev, sizeof (int) * ntoksz);
1969
1970	if ((tokset == NULL) || (toklev == NULL))
1971/*
1972 * TRANSLATION_NOTE  -- This is a message from yacc.
1973 *	This message is passed to error() function.
1974 *	Do not translate NTERMS.
1975 *
1976 *	You may just translate this as:
1977 *	'Could not allocate internally used memory.'
1978 */
1979		error(gettext(
1980		"couldn't expand NTERMS"));
1981}
1982
1983
1984static void
1985exp_nonterm()
1986{
1987	nnontersz += NNONTERM;
1988
1989	nontrst = (NTSYMB *)
1990	    realloc((char *)nontrst, sizeof (TOKSYMB) * nnontersz);
1991	if (nontrst == NULL)
1992/*
1993 * TRANSLATION_NOTE  -- This is a message from yacc.
1994 *	This message is passed to error() function.
1995 *	Do not translate NTERMS.
1996 *
1997 *	You may just translate this as:
1998 *	'Could not allocate internally used memory.'
1999 */
2000		error(gettext(
2001		"couldn't expand NNONTERM"));
2002}
2003
2004void
2005exp_mem(flag)
2006int flag;
2007{
2008	int i;
2009	static int *membase;
2010	new_memsize += MEMSIZE;
2011
2012	membase = tracemem;
2013	tracemem = (int *)
2014		realloc((char *)tracemem, sizeof (int) * new_memsize);
2015	if (tracemem == NULL)
2016/*
2017 * TRANSLATION_NOTE  -- This is a message from yacc.
2018 *	This message is passed to error() function.
2019 *
2020 *	You may just translate this as:
2021 *	'Could not allocate internally used memory.'
2022 */
2023		error(gettext(
2024		"couldn't expand mem table"));
2025	if (flag) {
2026		for (i = 0; i <= nprod; ++i)
2027			prdptr[i] = prdptr[i] - membase + tracemem;
2028		mem = mem - membase + tracemem;
2029	} else {
2030		size += MEMSIZE;
2031		temp1 = (int *)realloc((char *)temp1, sizeof (int)*size);
2032		optimmem = optimmem - membase + tracemem;
2033	}
2034}
2035
2036static int
2037findchtok(chlit)
2038int chlit;
2039/*
2040 * findchtok(chlit) returns the token number for a character literal
2041 * chlit that is "bigger" than 255 -- the max char value that the
2042 * original yacc was build for.  This yacc treate them as though
2043 * an ordinary token.
2044 */
2045{
2046	int	i;
2047
2048	if (chlit < 0xff)
2049		return (chlit); /* single-byte char */
2050	for (i = 0; i < nmbchars; ++i) {
2051		if (mbchars->character == chlit)
2052			return (mbchars->tvalue);
2053	}
2054
2055	/* Not found.  Register it! */
2056	if (++nmbchars > nmbcharsz) { /* Make sure there's enough space */
2057		nmbcharsz += NMBCHARSZ;
2058		mbchars = (MBCLIT *)
2059		    realloc((char *)mbchars, sizeof (MBCLIT)*nmbcharsz);
2060		if (mbchars == NULL)
2061			error(gettext(
2062			"too many character literals"));
2063	}
2064	mbchars[nmbchars-1].character = chlit;
2065	return (mbchars[nmbchars-1].tvalue = extval++);
2066	/* Return the newly assigned token. */
2067}
2068
2069/*
2070 * When -p is specified, symbol prefix for
2071 *	yy{parse, lex, error}(),
2072 *	yy{lval, val, char, debug, errflag, nerrs}
2073 * are defined to the specified name.
2074 */
2075static void
2076put_prefix_define(char *pre)
2077{
2078	char *syms[] = {
2079		/* Functions */
2080		"parse",
2081		"lex",
2082		"error",
2083		/* Variables */
2084		"lval",
2085		"val",
2086		"char",
2087		"debug",
2088		"errflag",
2089		"nerrs",
2090		NULL};
2091	int i;
2092
2093	for (i = 0; syms[i]; i++)
2094		(void) fprintf(ftable, "#define\tyy%s\t%s%s\n",
2095		    syms[i], pre, syms[i]);
2096}
2097