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