xref: /illumos-gate/usr/src/cmd/sgs/yacc/common/y2.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 = (wchar_t *)malloc(sizeof (wchar_t) * toksize);
189 	tokset = (TOKSYMB *)malloc(sizeof (TOKSYMB) * ntoksz);
190 	toklev = (int *)malloc(sizeof (int) * ntoksz);
191 	nontrst = (NTSYMB *)malloc(sizeof (NTSYMB) * nnontersz);
192 	mem0 = (int *)malloc(sizeof (int) * new_memsize);
193 	prdptr = (int **)malloc(sizeof (int *) * (nprodsz+2));
194 	levprd = (int *)malloc(sizeof (int) * (nprodsz+2));
195 	had_act = (wchar_t *)calloc((nprodsz + 2), sizeof (wchar_t));
196 	lhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * LHS_TEXT_LEN);
197 	rhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * RHS_TEXT_LEN);
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, gettext(
506 				"redeclaration of precedence of %ws."),
507 						    tokname);
508 						SETASC(toklev[j], lev);
509 						}
510 					if (ty) {
511 						if (TYPE(toklev[j]))
512 							error(gettext(
513 /*
514  * TRANSLATION_NOTE  -- This is a message from yacc.
515  *	This message is passed to error() function.
516  */
517 						"redeclaration of type of %ws"),
518 							    tokname);
519 						SETTYPE(toklev[j], ty);
520 						}
521 					if ((t = gettok()) == NUMBER) {
522 						tokset[j].value = numbval;
523 						if (j < ndefout && j > 2) {
524 /*
525  * TRANSLATION_NOTE  -- This is a message from yacc.
526  *	This message is passed to error() function.
527  */
528 							error(gettext(
529 				"type number of %ws should be defined earlier"),
530 							    tokset[j].name);
531 							}
532 						if (numbval >= -YYFLAG1) {
533 /*
534  * TRANSLATION_NOTE  -- This is a message from yacc.
535  *	This message is passed to error() function.
536  */
537 							error(gettext(
538 				"token numbers must be less than %d"),
539 							    -YYFLAG1);
540 							}
541 						t = gettok();
542 						}
543 					continue;
544 
545 					}
546 				if (!tok_in_line)
547 /*
548  * TRANSLATION_NOTE  -- This is a message from yacc.
549  *	This message is passed to error() function.
550  */
551 					error(gettext(
552 					"missing tokens or illegal tokens"));
553 				break;
554 				}
555 			continue;
556 
557 		case LCURLY:
558 			defout();
559 			cpycode();
560 			t = gettok();
561 			continue;
562 
563 		default:
564 			error("syntax error");
565 
566 			}
567 
568 		}
569 
570 	if (t == ENDFILE) {
571 /*
572  * TRANSLATION_NOTE  -- This is a message from yacc.
573  *	This message is passed to error() function.
574  *	Do not translate %%%%.
575  */
576 		error("unexpected EOF before %%%%");
577 		}
578 
579 	/* t is MARK */
580 
581 	defout();
582 	end_toks();	/* all tokens dumped - get ready for reductions */
583 
584 	(void) fprintf(ftable, "\n#include <inttypes.h>\n");
585 	(void) fprintf(ftable, "\n#ifdef __STDC__\n");
586 	(void) fprintf(ftable, "#include <stdlib.h>\n");
587 	(void) fprintf(ftable, "#include <string.h>\n");
588 	(void) fprintf(ftable, "#define	YYCONST	const\n");
589 	(void) fprintf(ftable, "#else\n");
590 	(void) fprintf(ftable, "#include <malloc.h>\n");
591 	(void) fprintf(ftable, "#include <memory.h>\n");
592 	(void) fprintf(ftable, "#define	YYCONST\n");
593 	(void) fprintf(ftable, "#endif\n");
594 	(void) fprintf(ftable, "\n#include <values.h>\n");
595 
596 	if (sym_prefix[0] != '\0')
597 		put_prefix_define(sym_prefix);
598 
599 	(void) fprintf(ftable,
600 	    "\n#if defined(__cplusplus) || defined(__STDC__)\n");
601 	(void) fprintf(ftable,
602 	    "\n#if defined(__cplusplus) && defined(__EXTERN_C__)\n");
603 	(void) fprintf(ftable, "extern \"C\" {\n");
604 	(void) fprintf(ftable, "#endif\n");
605 	(void) fprintf(ftable, "#ifndef yyerror\n");
606 	(void) fprintf(ftable, "#if defined(__cplusplus)\n");
607 	(void) fprintf(ftable, "	void yyerror(YYCONST char *);\n");
608 	(void) fprintf(ftable, "#endif\n");
609 	(void) fprintf(ftable, "#endif\n");
610 	(void) fprintf(ftable, "#ifndef yylex\n");
611 	(void) fprintf(ftable, "	int yylex(void);\n");
612 	(void) fprintf(ftable, "#endif\n");
613 	(void) fprintf(ftable, "	int yyparse(void);\n");
614 	(void) fprintf(ftable,
615 	    "#if defined(__cplusplus) && defined(__EXTERN_C__)\n");
616 	(void) fprintf(ftable, "}\n");
617 	(void) fprintf(ftable, "#endif\n");
618 	(void) fprintf(ftable, "\n#endif\n\n");
619 
620 	(void) fprintf(ftable, "#define yyclearin yychar = -1\n");
621 	(void) fprintf(ftable, "#define yyerrok yyerrflag = 0\n");
622 	(void) fprintf(ftable, "extern int yychar;\nextern int yyerrflag;\n");
623 	if (!(defunion || ntypes))
624 		(void) fprintf(ftable,
625 		    "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
626 	(void) fprintf(ftable, "YYSTYPE yylval;\n");
627 	(void) fprintf(ftable, "YYSTYPE yyval;\n");
628 	(void) fprintf(ftable, "typedef int yytabelem;\n");
629 	(void) fprintf(ftable,
630 	    "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n");
631 	(void) fprintf(ftable, "#if YYMAXDEPTH > 0\n");
632 	(void) fprintf(ftable, "int yy_yys[YYMAXDEPTH], *yys = yy_yys;\n");
633 	(void) fprintf(ftable, "YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;\n");
634 	(void) fprintf(ftable, "#else	/* user does initial allocation */\n");
635 	(void) fprintf(ftable, "int *yys;\nYYSTYPE *yyv;\n#endif\n");
636 	(void) fprintf(ftable, "static int yymaxdepth = YYMAXDEPTH;\n");
637 
638 	prdptr[0] = mem;
639 	/* added production */
640 	*mem++ = NTBASE;
641 
642 	/* if start is 0, we will overwrite with the lhs of the first rule */
643 	*mem++ = start;
644 	*mem++ = 1;
645 	*mem++ = 0;
646 	prdptr[1] = mem;
647 
648 	while ((t = gettok()) == LCURLY)
649 		cpycode();
650 
651 	if (t != C_IDENTIFIER)
652 		error("bad syntax on first rule");
653 
654 	if (!start)
655 		prdptr[0][1] = chfind(1, tokname);
656 
657 	/* read rules */
658 
659 	while (t != MARK && t != ENDFILE) {
660 
661 		/* process a rule */
662 
663 		if (t == L'|') {
664 			rhsfill((wchar_t *)0); /* restart fill of rhs */
665 			*mem = *prdptr[nprod-1];
666 			if (++mem >= &tracemem[new_memsize])
667 				exp_mem(1);
668 		} else if (t == C_IDENTIFIER) {
669 			*mem = chfind(1, tokname);
670 			if (*mem < NTBASE)
671 /*
672  * TRANSLATION_NOTE  -- This is a message from yacc.
673  *	This message is passed to error() function.
674  *	Check how nonterminal is translated.
675  */
676 				error(gettext(
677 				"illegal nonterminal in grammar rule"));
678 			if (++mem >= &tracemem[new_memsize])
679 				exp_mem(1);
680 			lhsfill(tokname);	/* new rule: restart strings */
681 		} else
682 /*
683  * TRANSLATION_NOTE  -- This is a message from yacc.
684  *	This message is passed to error() function.
685  */
686 			error(gettext(
687 			"illegal rule: missing semicolon or | ?"));
688 
689 		/* read rule body */
690 
691 
692 		t = gettok();
693 	more_rule:
694 		while (t == IDENTIFIER) {
695 			*mem = chfind(1, tokname);
696 			if (*mem < NTBASE)
697 				levprd[nprod] = toklev[*mem]& ~04;
698 			if (++mem >= &tracemem[new_memsize])
699 				exp_mem(1);
700 			rhsfill(tokname);	/* add to rhs string */
701 			t = gettok();
702 			}
703 
704 		if (t == PREC) {
705 			if (gettok() != IDENTIFIER)
706 /*
707  * TRANSLATION_NOTE  -- This is a message from yacc.
708  *	This message is passed to error() function.
709  *	Do not translate %%prec.
710  */
711 				error(gettext(
712 				    "illegal %%prec syntax"));
713 			j = chfind(2, tokname);
714 			if (j >= NTBASE)
715 /*
716  * TRANSLATION_NOTE  -- This is a message from yacc.
717  *	This message is passed to error() function.
718  *	Do not translate %%prec.
719  */
720 				error(gettext(
721 				    "nonterminal %ws illegal after %%prec"),
722 				    nontrst[j-NTBASE].name);
723 			levprd[nprod] = toklev[j] & ~04;
724 			t = gettok();
725 			}
726 
727 		if (t == L'=') {
728 			had_act[nprod] = 1;
729 			levprd[nprod] |= ACTFLAG;
730 			(void) fprintf(faction, "\ncase %d:", nprod);
731 			cpyact(mem-prdptr[nprod] - 1);
732 			(void) fprintf(faction, " break;");
733 			if ((t = gettok()) == IDENTIFIER) {
734 				/* action within rule... */
735 
736 				lrprnt();		/* dump lhs, rhs */
737 				(void) wsprintf(actname, "$$%d", nprod);
738 				/*
739 				 * make it nonterminal
740 				 */
741 				j = chfind(1, actname);
742 
743 				/*
744 				 * the current rule will become rule
745 				 * number nprod+1 move the contents down,
746 				 * and make room for the null
747 				 */
748 
749 				if (mem + 2 >= &tracemem[new_memsize])
750 					exp_mem(1);
751 				for (p = mem; p >= prdptr[nprod]; --p)
752 					p[2] = *p;
753 				mem += 2;
754 
755 				/* enter null production for action */
756 
757 				p = prdptr[nprod];
758 
759 				*p++ = j;
760 				*p++ = -nprod;
761 
762 				/* update the production information */
763 
764 				levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
765 				levprd[nprod] = ACTFLAG;
766 
767 				if (++nprod >= nprodsz)
768 					exp_prod();
769 				prdptr[nprod] = p;
770 
771 				/*
772 				 * make the action appear in
773 				 * the original rule
774 				 */
775 				*mem++ = j;
776 				if (mem >= &tracemem[new_memsize])
777 					exp_mem(1);
778 				/* get some more of the rule */
779 				goto more_rule;
780 			}
781 		}
782 		while (t == L';')
783 			t = gettok();
784 		*mem++ = -nprod;
785 		if (mem >= &tracemem[new_memsize])
786 			exp_mem(1);
787 
788 		/* check that default action is reasonable */
789 
790 		if (ntypes && !(levprd[nprod] & ACTFLAG) &&
791 		    nontrst[*prdptr[nprod]-NTBASE].tvalue) {
792 			/* no explicit action, LHS has value */
793 			int tempty;
794 
795 			tempty = prdptr[nprod][1];
796 			if (tempty < 0)
797 /*
798  * TRANSLATION_NOTE  -- This is a message from yacc.
799  *	This message is passed to error() function.
800  *	LHS means Left Hand Side. It does not need to be translated.
801  */
802 				error(gettext(
803 				"must return a value, since LHS has a type"));
804 			else if (tempty >= NTBASE)
805 				tempty = nontrst[tempty-NTBASE].tvalue;
806 			else
807 				tempty = TYPE(toklev[tempty]);
808 			if (tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue) {
809 /*
810  * TRANSLATION_NOTE  -- This is a message from yacc.
811  *	This message is passed to error() function.
812  *	Check how action is transltated in yacc man page or documents.
813  */
814 				error(gettext(
815 				"default action causes potential type clash"));
816 			}
817 		}
818 
819 		if (++nprod >= nprodsz)
820 			exp_prod();
821 		prdptr[nprod] = mem;
822 		levprd[nprod] = 0;
823 		}
824 	/* end of all rules */
825 
826 	end_debug();		/* finish fdebug file's input */
827 	finact();
828 	if (t == MARK) {
829 		if (gen_lines)
830 			(void) fprintf(ftable, "\n# line %d \"%s\"\n",
831 			    lineno, infile);
832 		while ((c = getwc(finput)) != EOF)
833 			(void) putwc(c, ftable);
834 	}
835 	(void) fclose(finput);
836 }
837 
838 static void
839 finact(void)
840 {
841 	/* finish action routine */
842 	(void) fclose(faction);
843 	(void) fprintf(ftable, "# define YYERRCODE %d\n", tokset[2].value);
844 }
845 
846 static wchar_t *
847 cstash(wchar_t *s)
848 {
849 	wchar_t *temp;
850 	static int used = 0;
851 	static int used_save = 0;
852 	static int exp_cname = CNAMSZ;
853 	int len = wslen(s);
854 
855 	/*
856 	 * 2/29/88 -
857 	 * Don't need to expand the table, just allocate new space.
858 	 */
859 	used_save = used;
860 	while (len >= (exp_cname - used_save)) {
861 		exp_cname += CNAMSZ;
862 		if (!used)
863 			free((char *)cnames);
864 		if ((cnames = (wchar_t *)
865 		    malloc(sizeof (wchar_t)*exp_cname)) == NULL)
866 /*
867  * TRANSLATION_NOTE  -- This is a message from yacc.
868  *	This message is passed to error() function.
869  *
870  *	You may just translate this as:
871  *	'Could not allocate internally used memory.'
872  */
873 			error(gettext(
874 			    "cannot expand string dump"));
875 		cnamp = cnames;
876 		used = 0;
877 	}
878 
879 	temp = cnamp;
880 	do {
881 		*cnamp++ = *s;
882 	} while (*s++);
883 	used += cnamp - temp;
884 	return (temp);
885 }
886 
887 static int
888 defin(int t, wchar_t *s)
889 {
890 	/* define s to be a terminal if t=0 or a nonterminal if t=1 */
891 
892 	int val = 0;
893 
894 	if (t) {
895 		if (++nnonter >= nnontersz)
896 			exp_nonterm();
897 		nontrst[nnonter].name = cstash(s);
898 		return (NTBASE + nnonter);
899 		}
900 	/* must be a token */
901 	if (++ntokens >= ntoksz)
902 		exp_ntok();
903 	tokset[ntokens].name = cstash(s);
904 
905 	/* establish value for token */
906 
907 	if (s[0] == L' ' && s[2] == 0) { /* single character literal */
908 		val = findchtok(s[1]);
909 	} else if (s[0] == L' ' && s[1] == L'\\') { /* escape sequence */
910 		if (s[3] == 0) { /* single character escape sequence */
911 			switch (s[2]) {
912 				/* character which is escaped */
913 			case L'a':
914 				(void) warning(1, gettext(
915 /*
916  * TRANSLATION_NOTE  -- This is a message from yacc.
917  *	This message is passed to warning() function.
918  *	Do not trasnlate ANSI C, \\a.
919  */
920 		"\\a is ANSI C \"alert\" character"));
921 #if __STDC__ - 1 == 0
922 				val = L'\a';
923 				break;
924 #else
925 				val = L'\007';
926 				break;
927 #endif
928 			case L'v': val = L'\v'; break;
929 			case L'n': val = L'\n'; break;
930 			case L'r': val = L'\r'; break;
931 			case L'b': val = L'\b'; break;
932 			case L't': val = L'\t'; break;
933 			case L'f': val = L'\f'; break;
934 			case L'\'': val = L'\''; break;
935 			case L'"': val = L'"'; break;
936 			case L'?': val = L'?'; break;
937 			case L'\\': val = L'\\'; break;
938 /*
939  * TRANSLATION_NOTE  -- This is a message from yacc.
940  *	This message is passed to error() function.
941  */
942 			default: error(gettext(
943 				"invalid escape"));
944 			}
945 		} else if (s[2] <= L'7' && s[2] >= L'0') { /* \nnn sequence */
946 			int i = 3;
947 			val = s[2] - L'0';
948 			while (iswdigit(s[i]) && i <= 4) {
949 				if (s[i] >= L'0' && s[i] <= L'7')
950 					val = val * 8 + s[i] - L'0';
951 				else
952 /*
953  * TRANSLATION_NOTE  -- This is a message from yacc.
954  *	This message is passed to error() function.
955  */
956 					error(gettext(
957 					"illegal octal number"));
958 				i++;
959 			}
960 			if (s[i] != 0)
961 /*
962  * TRANSLATION_NOTE  -- This is a message from yacc.
963  *	This message is passed to error() function.
964  *	Do not translate \\nnn.
965  */
966 				error(gettext(
967 				"illegal \\nnn construction"));
968 			if (val > 255)
969 /*
970  * TRANSLATION_NOTE  -- This is a message from yacc.
971  *	This message is passed to error() function.
972  *	Do not translate
973  *		\\nnn, \\xnnnnnnnn.
974  */
975 				error(
976 "\\nnn exceed \\377; use \\xnnnnnnnn for wchar_t value of multibyte char");
977 			if (val == 0 && i >= 4)
978 /*
979  * TRANSLATION_NOTE  -- This is a message from yacc.
980  *	This message is passed to error() function.
981  *	Do not translate \\000.
982  */
983 				error(gettext(
984 				"'\\000' is illegal"));
985 		} else if (s[2] == L'x') { /* hexadecimal \xnnn sequence */
986 			int i = 3;
987 			val = 0;
988 /*
989  * TRANSLATION_NOTE  -- This is a message from yacc.
990  *	This message is passed to warning() function.
991  *	Do not translate \\x, ANSI C.
992  */
993 			(void) warning(1, gettext(
994 			    "\\x is ANSI C hex escape"));
995 			if (iswxdigit(s[i]))
996 				while (iswxdigit(s[i])) {
997 					int tmpval;
998 					if (iswdigit(s[i]))
999 						tmpval = s[i] - L'0';
1000 					else if (s[i] >= L'a')
1001 						tmpval = s[i] - L'a' + 10;
1002 					else
1003 						tmpval = s[i] - L'A' + 10;
1004 					val = 16 * val + tmpval;
1005 					i++;
1006 				}
1007 			else
1008 				error(gettext(
1009 				"illegal hexadecimal number"));
1010 			if (s[i] != 0)
1011 /*
1012  * TRANSLATION_NOTE  -- This is a message from yacc.
1013  *	This message is passed to error() function.
1014  *	Do not translate \\xnn.
1015  */
1016 				error(gettext(
1017 				"illegal \\xnn construction"));
1018 #define	LWCHAR_MAX	0x7fffffff
1019 			if ((unsigned)val > LWCHAR_MAX)
1020 /*
1021  * TRANSLATION_NOTE  -- This is a message from yacc.
1022  *	This message is passed to error() function.
1023  *	Do not translate \\xnnnnnnnn and %#x.
1024  */
1025 				error(gettext(
1026 				    " \\xnnnnnnnn exceed %#x"),
1027 				    LWCHAR_MAX);
1028 			if (val == 0)
1029 /*
1030  * TRANSLATION_NOTE  -- This is a message from yacc.
1031  *	This message is passed to error() function.
1032  *	Do not translate \\x00.
1033  */
1034 				error(gettext(
1035 				"'\\x00' is illegal"));
1036 			val = findchtok(val);
1037 		} else
1038 			error(gettext(
1039 			"invalid escape"));
1040 	} else {
1041 		val = extval++;
1042 	}
1043 	tokset[ntokens].value = val;
1044 	toklev[ntokens] = 0;
1045 	return (ntokens);
1046 }
1047 
1048 static void
1049 defout(void)
1050 {
1051 	/* write out the defines (at the end of the declaration section) */
1052 
1053 	register int i, c;
1054 	register wchar_t *cp;
1055 
1056 	for (i = ndefout; i <= ntokens; ++i) {
1057 
1058 		cp = tokset[i].name;
1059 		if (*cp == L' ')	/* literals */
1060 		{
1061 			(void) fprintf(fdebug, WSFMT("\t\"%ws\",\t%d,\n"),
1062 			    tokset[i].name + 1, tokset[i].value);
1063 			continue;	/* was cp++ */
1064 		}
1065 
1066 		for (; (c = *cp) != 0; ++cp) {
1067 			if (iswlower(c) || iswupper(c) ||
1068 			    iswdigit(c) || c == L'_')
1069 				/* EMPTY */;
1070 			else
1071 				goto nodef;
1072 		}
1073 
1074 		(void) fprintf(fdebug,
1075 		    WSFMT("\t\"%ws\",\t%d,\n"), tokset[i].name,
1076 		    tokset[i].value);
1077 		(void) fprintf(ftable,
1078 		    WSFMT("# define %ws %d\n"), tokset[i].name,
1079 		    tokset[i].value);
1080 		if (fdefine != NULL)
1081 			(void) fprintf(fdefine,
1082 			    WSFMT("# define %ws %d\n"),
1083 			    tokset[i].name,
1084 			    tokset[i].value);
1085 
1086 	nodef:;
1087 	}
1088 	ndefout = ntokens+1;
1089 }
1090 
1091 static int
1092 gettok(void)
1093 {
1094 	int i, base;
1095 	static int peekline; /* number of '\n' seen in lookahead */
1096 	int c, match, reserve;
1097 begin:
1098 	reserve = 0;
1099 	lineno += peekline;
1100 	peekline = 0;
1101 	c = getwc(finput);
1102 	/*
1103 	 * while (c == ' ' || c == '\n' || c == '\t' || c == '\f') {
1104 	 */
1105 	while (iswspace(c)) {
1106 		if (c == L'\n')
1107 			++lineno;
1108 		c = getwc(finput);
1109 	}
1110 	if (c == L'/') { /* skip comment */
1111 		lineno += skipcom();
1112 		goto begin;
1113 	}
1114 
1115 	switch (c) {
1116 
1117 	case EOF:
1118 		return (ENDFILE);
1119 	case L'{':
1120 		(void) ungetwc(c, finput);
1121 		return (L'=');  /* action ... */
1122 	case L'<':  /* get, and look up, a type name (union member name) */
1123 		i = 0;
1124 		while ((c = getwc(finput)) != L'>' &&
1125 		    c != EOF && c != L'\n') {
1126 			tokname[i] = c;
1127 			if (++i >= toksize)
1128 				exp_tokname();
1129 			}
1130 		if (c != L'>')
1131 			error(gettext(
1132 			"unterminated < ... > clause"));
1133 		tokname[i] = 0;
1134 		if (i == 0)
1135 			error("missing type name in < ... > clause");
1136 		for (i = 1; i <= ntypes; ++i) {
1137 			if (!wscmp(typeset[i], tokname)) {
1138 				numbval = i;
1139 				return (TYPENAME);
1140 				}
1141 			}
1142 		typeset[numbval = ++ntypes] = cstash(tokname);
1143 		return (TYPENAME);
1144 
1145 	case L'"':
1146 	case L'\'':
1147 		match = c;
1148 		tokname[0] = L' ';
1149 		i = 1;
1150 		for (;;) {
1151 			c = getwc(finput);
1152 			if (c == L'\n' || c == EOF)
1153 				error(gettext(
1154 				"illegal or missing ' or \""));
1155 			if (c == L'\\') {
1156 				c = getwc(finput);
1157 				tokname[i] = L'\\';
1158 				if (++i >= toksize)
1159 					exp_tokname();
1160 			} else if (c == match) break;
1161 			tokname[i] = c;
1162 			if (++i >= toksize)
1163 				exp_tokname();
1164 			}
1165 		break;
1166 
1167 	case L'%':
1168 	case L'\\':
1169 
1170 		switch (c = getwc(finput)) {
1171 
1172 		case L'0':	return (TERM);
1173 		case L'<':	return (LEFT);
1174 		case L'2':	return (BINARY);
1175 		case L'>':	return (RIGHT);
1176 		case L'%':
1177 		case L'\\':	return (MARK);
1178 		case L'=':	return (PREC);
1179 		case L'{':	return (LCURLY);
1180 		default:	reserve = 1;
1181 		}
1182 		/* FALLTHROUGH */
1183 	default:
1184 
1185 		if (iswdigit(c)) { /* number */
1186 			numbval = c - L'0';
1187 			base = (c == L'0') ? 8 : 10;
1188 			for (c = getwc(finput);
1189 			    iswdigit(c);
1190 			    c = getwc(finput)) {
1191 				numbval = numbval*base + c - L'0';
1192 				}
1193 			(void) ungetwc(c, finput);
1194 			return (NUMBER);
1195 		} else if (iswlower(c) || iswupper(c) ||
1196 		    c == L'_' || c == L'.' ||
1197 		    c == L'$') {
1198 			i = 0;
1199 			while (iswlower(c) || iswupper(c) ||
1200 			    iswdigit(c) || c == L'_' ||
1201 			    c == L'.' || c == L'$') {
1202 				tokname[i] = c;
1203 				if (reserve && iswupper(c))
1204 					tokname[i] = towlower(c);
1205 				if (++i >= toksize)
1206 					exp_tokname();
1207 				c = getwc(finput);
1208 				}
1209 			}
1210 		else
1211 			return (c);
1212 
1213 		(void) ungetwc(c, finput);
1214 		}
1215 
1216 	tokname[i] = 0;
1217 
1218 	if (reserve) { /* find a reserved word */
1219 		if (!wscmp(tokname, L"term"))
1220 			return (TERM);
1221 		if (!wscmp(tokname, L"token"))
1222 			return (TERM);
1223 		if (!wscmp(tokname, L"left"))
1224 			return (LEFT);
1225 		if (!wscmp(tokname, L"nonassoc"))
1226 			return (BINARY);
1227 		if (!wscmp(tokname, L"binary"))
1228 			return (BINARY);
1229 		if (!wscmp(tokname, L"right"))
1230 			return (RIGHT);
1231 		if (!wscmp(tokname, L"prec"))
1232 			return (PREC);
1233 		if (!wscmp(tokname, L"start"))
1234 			return (START);
1235 		if (!wscmp(tokname, L"type"))
1236 			return (TYPEDEF);
1237 		if (!wscmp(tokname, L"union"))
1238 			return (UNION);
1239 		error(gettext(
1240 		    "invalid escape, or illegal reserved word: %ws"),
1241 		    tokname);
1242 		}
1243 
1244 	/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
1245 
1246 	c = getwc(finput);
1247 	/*
1248 	 * while (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '/')
1249 	 * {
1250 	 */
1251 	while (iswspace(c) || c == L'/') {
1252 		if (c == L'\n') {
1253 			++peekline;
1254 		} else if (c == L'/') { /* look for comments */
1255 			peekline += skipcom();
1256 			}
1257 		c = getwc(finput);
1258 		}
1259 	if (c == L':')
1260 		return (C_IDENTIFIER);
1261 	(void) ungetwc(c, finput);
1262 	return (IDENTIFIER);
1263 }
1264 
1265 static int
1266 fdtype(int t)
1267 {
1268 	/* determine the type of a symbol */
1269 	int v;
1270 	if (t >= NTBASE)
1271 		v = nontrst[t-NTBASE].tvalue;
1272 	else
1273 		v = TYPE(toklev[t]);
1274 	if (v <= 0)
1275 		error(gettext(
1276 		    "must specify type for %ws"),
1277 		    (t >= NTBASE) ? nontrst[t-NTBASE].name:
1278 		    tokset[t].name);
1279 	return (v);
1280 }
1281 
1282 static int
1283 chfind(int t, wchar_t *s)
1284 {
1285 	int i;
1286 
1287 	if (s[0] == ' ')
1288 		t = 0;
1289 	TLOOP(i) {
1290 		if (!wscmp(s, tokset[i].name)) {
1291 			return (i);
1292 		}
1293 	}
1294 	NTLOOP(i) {
1295 		if (!wscmp(s, nontrst[i].name)) {
1296 			return (i + NTBASE);
1297 		}
1298 	}
1299 	/* cannot find name */
1300 	if (t > 1)
1301 		error(gettext(
1302 		"%ws should have been defined earlier"), s);
1303 	return (defin(t, s));
1304 }
1305 
1306 static void
1307 cpyunion(void)
1308 {
1309 	/*
1310 	 * copy the union declaration to the output,
1311 	 * and the define file if present
1312 	 */
1313 	int level, c;
1314 	if (gen_lines)
1315 		(void) fprintf(ftable, "\n# line %d \"%s\"\n", lineno, infile);
1316 	(void) fprintf(ftable, "typedef union\n");
1317 	if (fdefine)
1318 		(void) fprintf(fdefine, "\ntypedef union\n");
1319 	(void) fprintf(ftable, "#ifdef __cplusplus\n\tYYSTYPE\n#endif\n");
1320 	if (fdefine)
1321 		(void) fprintf(fdefine,
1322 		    "#ifdef __cplusplus\n\tYYSTYPE\n#endif\n");
1323 
1324 	level = 0;
1325 	for (;;) {
1326 		if ((c = getwc(finput)) == EOF)
1327 /*
1328  * TRANSLATION_NOTE  -- This is a message from yacc.
1329  *	This message is passed to error() function.
1330  *	EOF - End Of File.
1331  *	Do not translate %%union.
1332  */
1333 			error(gettext(
1334 			"EOF encountered while processing %%union"));
1335 		(void) putwc(c, ftable);
1336 		if (fdefine)
1337 			(void) putwc(c, fdefine);
1338 
1339 		switch (c) {
1340 
1341 		case L'\n':
1342 			++lineno;
1343 			break;
1344 
1345 		case L'{':
1346 			++level;
1347 			break;
1348 
1349 		case L'}':
1350 			--level;
1351 			if (level == 0) { /* we are finished copying */
1352 				(void) fprintf(ftable, " YYSTYPE;\n");
1353 				if (fdefine)
1354 					(void) fprintf(fdefine,
1355 					" YYSTYPE;\nextern YYSTYPE yylval;\n");
1356 				return;
1357 				}
1358 			}
1359 		}
1360 }
1361 
1362 static void
1363 cpycode(void)
1364 {
1365 	/* copies code between \{ and \} */
1366 
1367 	int c;
1368 	c = getwc(finput);
1369 	if (c == L'\n') {
1370 		c = getwc(finput);
1371 		lineno++;
1372 		}
1373 	if (gen_lines)
1374 		(void) fprintf(ftable, "\n# line %d \"%s\"\n", lineno, infile);
1375 	while (c != EOF) {
1376 		if (c == L'\\') {
1377 			if ((c = getwc(finput)) == L'}')
1378 				return;
1379 			else
1380 				(void) putwc(L'\\', ftable);
1381 		} else if (c == L'%') {
1382 			if ((c = getwc(finput)) == L'}')
1383 				return;
1384 			else
1385 				(void) putwc(L'%', ftable);
1386 		}
1387 		(void) putwc(c, ftable);
1388 		if (c == L'\n')
1389 			++lineno;
1390 		c = getwc(finput);
1391 		}
1392 /*
1393  * TRANSLATION_NOTE  -- This is a message from yacc.
1394  *	This message is passed to error() function.
1395  *	Do not translate %%}.
1396  */
1397 	error(gettext(
1398 	"eof before %%}"));
1399 }
1400 
1401 static int
1402 skipcom(void)
1403 {
1404 	/* skip over comments */
1405 	int c, i = 0;  /* i is the number of lines skipped */
1406 
1407 	/* skipcom is called after reading a / */
1408 
1409 	if (getwc(finput) != L'*')
1410 		error(gettext(
1411 		"illegal comment"));
1412 	c = getwc(finput);
1413 	while (c != EOF) {
1414 		while (c == L'*') {
1415 			if ((c = getwc(finput)) == L'/')
1416 				return (i);
1417 			}
1418 		if (c == L'\n')
1419 			++i;
1420 		c = getwc(finput);
1421 		}
1422 /*
1423  * TRANSLATION_NOTE  -- This is a message from yacc.
1424  *	This message is passed to error() function.
1425  *	EOF -- End Of File.
1426  */
1427 	error(gettext(
1428 	"EOF inside comment"));
1429 	/* NOTREACHED */
1430 	return (0);
1431 }
1432 
1433 static void
1434 cpyact(int offset)
1435 {
1436 	/* copy C action to the next ; or closing } */
1437 	int brac, c, match, i, t, j, s, tok, argument, m;
1438 	wchar_t id_name[NAMESIZE+1];
1439 	int id_idx = 0;
1440 
1441 	if (gen_lines) {
1442 		(void) fprintf(faction, "\n# line %d \"%s\"\n", lineno, infile);
1443 		act_lines++;
1444 	}
1445 	brac = 0;
1446 	id_name[0] = 0;
1447 loop:
1448 	c = getwc(finput);
1449 swt:
1450 	switch (c) {
1451 	case L';':
1452 		if (brac == 0) {
1453 			(void) putwc(c, faction);
1454 			return;
1455 		}
1456 		goto lcopy;
1457 	case L'{':
1458 		brac++;
1459 		goto lcopy;
1460 	case L'$':
1461 		s = 1;
1462 		tok = -1;
1463 		argument = 1;
1464 		while ((c = getwc(finput)) == L' ' || c == L'\t')
1465 			/* NULL */;
1466 		if (c == L'<') { /* type description */
1467 			(void) ungetwc(c, finput);
1468 			if (gettok() != TYPENAME)
1469 /*
1470  * TRANSLATION_NOTE  -- This is a message from yacc.
1471  *	This message is passed to error() function.
1472  *	Do not translate $<ident>
1473  */
1474 				error(gettext(
1475 				"bad syntax on $<ident> clause"));
1476 			tok = numbval;
1477 			c = getwc(finput);
1478 		}
1479 		if (c == L'$') {
1480 			(void) fprintf(faction, "yyval");
1481 			if (ntypes) { /* put out the proper tag... */
1482 				if (tok < 0)
1483 					tok = fdtype(*prdptr[nprod]);
1484 				(void) fprintf(faction,
1485 				    WSFMT(".%ws"), typeset[tok]);
1486 			}
1487 			goto loop;
1488 		}
1489 		if (iswalpha(c)) {
1490 			int same = 0;
1491 			int id_sw = 0;
1492 			(void) ungetwc(c, finput);
1493 			if (gettok() != IDENTIFIER)
1494 /*
1495  * TRANSLATION_NOTE  -- This is a message from yacc.
1496  *	This message is passed to error() function.
1497  *	Check how action is translated in yacc man page/document.
1498  */
1499 				error(gettext(
1500 				"bad action format"));
1501 			/*
1502 			 * Save the number of non-terminal
1503 			 */
1504 			id_sw = nnonter;
1505 			t = chfind(1, tokname);
1506 			/*
1507 			 * Check if the identifier is added as a non-terminal
1508 			 */
1509 			if (id_sw != nnonter)
1510 				id_sw = 1;
1511 			else
1512 				id_sw = 0;
1513 			while ((c = getwc(finput)) == L' ' ||
1514 			    c == L'\t')
1515 				/* NULL */;
1516 			if (c == L'#') {
1517 				while ((c = getwc(finput)) == L' ' ||
1518 				    c == L'\t')
1519 					/* NULL */;
1520 				if (iswdigit(c)) {
1521 					m = 0;
1522 					while (iswdigit(c)) {
1523 						m = m*10+c-L'0';
1524 						c = getwc(finput);
1525 					}
1526 					argument = m;
1527 				} else
1528 					error(gettext(
1529 					"illegal character \"#\""));
1530 			}
1531 			if (argument < 1)
1532 /*
1533  * TRANSLATION_NOTE  -- This is a message from yacc.
1534  *	This message is passed to error() function.
1535  *	Check how action is translated in yacc man page/document.
1536  */
1537 				error(gettext(
1538 				"illegal action argument no."));
1539 			for (i = 1; i <= offset; ++i)
1540 				if (prdptr[nprod][i] == t)
1541 					if (++same == argument) {
1542 						(void) fprintf(faction,
1543 						    "yypvt[-%d]", offset-i);
1544 						if (ntypes) {
1545 							if (tok < 0)
1546 								tok =
1547 								/* CSTYLED */
1548 								fdtype(prdptr[nprod][i]);
1549 							(void) fprintf(faction,
1550 							    WSFMT(".%ws"),
1551 							    typeset[tok]);
1552 						}
1553 						goto swt;
1554 					}
1555 			/*
1556 			 * This used to be handled as error.
1557 			 * Treat this as a valid C statement.
1558 			 * (Likely id with $ in.)
1559 			 * If non-terminal is added, remove it from the list.
1560 			 */
1561 			(void) fprintf(faction, WSFMT("$%ws"), tokname);
1562 /*
1563  * TRANSLATION_NOTE  -- This is a message from yacc.
1564  *	This message is passed to warning() function.
1565  *	Do not translate Ansi C.
1566  */
1567 			warning(1, gettext(
1568 	"Illegal character '$' in Ansi C symbol: %ws$%ws."),
1569 			    id_name, tokname);
1570 
1571 			if (id_sw == 1)
1572 				--nnonter;
1573 			goto swt;
1574 		}
1575 		if (c == '-') {
1576 			s = -s;
1577 			c = getwc(finput);
1578 		}
1579 		if (iswdigit(c)) {
1580 			j = 0;
1581 			while (iswdigit(c)) {
1582 				j = j*10 + c - L'0';
1583 				c = getwc(finput);
1584 			}
1585 			j = j*s - offset;
1586 			if (j > 0) {
1587 /*
1588  * TRANSLATION_NOTE  -- This is a message from yacc.
1589  *	This message is passed to error() function.
1590  *	Do not translate $%d.
1591  */
1592 				error(gettext(
1593 				    "Illegal use of $%d"),
1594 				    j + offset);
1595 			}
1596 			(void) fprintf(faction, "yypvt[-%d]", -j);
1597 			if (ntypes) { /* put out the proper tag */
1598 				if (j + offset <= 0 && tok < 0)
1599 /*
1600  * TRANSLATION_NOTE  -- This is a message from yacc.
1601  *	This message is passed to error() function.
1602  *	Do not translate $%d.
1603  */
1604 					error(gettext(
1605 					    "must specify type of $%d"),
1606 					    j + offset);
1607 				if (tok < 0)
1608 					tok = fdtype(prdptr[nprod][j+offset]);
1609 				(void) fprintf(faction,
1610 				    WSFMT(".%ws"), typeset[tok]);
1611 			}
1612 			goto swt;
1613 		}
1614 		(void) putwc(L'$', faction);
1615 		if (s < 0)
1616 			(void) putwc(L'-', faction);
1617 		goto swt;
1618 	case L'}':
1619 		if (--brac)
1620 			goto lcopy;
1621 		(void) putwc(c, faction);
1622 		return;
1623 	case L'/':	/* look for comments */
1624 		(void) putwc(c, faction);
1625 		c = getwc(finput);
1626 		if (c != L'*')
1627 			goto swt;
1628 		/* it really is a comment */
1629 		(void) putwc(c, faction);
1630 		c = getwc(finput);
1631 		while (c != EOF) {
1632 			while (c == L'*') {
1633 				(void) putwc(c, faction);
1634 				if ((c = getwc(finput)) == L'/')
1635 					goto lcopy;
1636 			}
1637 			(void) putwc(c, faction);
1638 			if (c == L'\n')
1639 				++lineno;
1640 			c = getwc(finput);
1641 		}
1642 		error("EOF inside comment");
1643 		/* FALLTHRU */
1644 	case L'\'':	/* character constant */
1645 	case L'"':	/* character string */
1646 		match = c;
1647 		(void) putwc(c, faction);
1648 		while ((c = getwc(finput)) != EOF) {
1649 			if (c == L'\\') {
1650 				(void) putwc(c, faction);
1651 				c = getwc(finput);
1652 				if (c == L'\n')
1653 					++lineno;
1654 			} else if (c == match)
1655 				goto lcopy;
1656 			else if (c == L'\n')
1657 /*
1658  * TRANSLATION_NOTE  -- This is a message from yacc.
1659  *	This message is passed to error() function.
1660  *	This error message is issued when
1661  *	quoted string has multiple lines.
1662  */
1663 				error(gettext(
1664 				"newline in string or char. const."));
1665 			(void) putwc(c, faction);
1666 		}
1667 		error(gettext(
1668 		"EOF in string or character constant"));
1669 		/* FALLTHRU */
1670 	case EOF:
1671 /*
1672  * TRANSLATION_NOTE  -- This is a message from yacc.
1673  *	This message is passed to error() function.
1674  *	Check how 'action' is translated in yacc mapage/document.
1675  */
1676 		error(gettext(
1677 		"action does not terminate"));
1678 		/* FALLTHRU */
1679 	case L'\n':
1680 		++lineno;
1681 		goto lcopy;
1682 	}
1683 lcopy:
1684 	(void) putwc(c, faction);
1685 	/*
1686 	 * Save the possible identifier name.
1687 	 * Used to print out a warning message.
1688 	 */
1689 	if (id_idx >= NAMESIZE) {
1690 		/*
1691 		 * Error. Silently ignore.
1692 		 */
1693 		/* EMPTY */;
1694 	}
1695 	/*
1696 	 * If c has a possibility to be a
1697 	 * part of identifier, save it.
1698 	 */
1699 	else if (iswalnum(c) || c == L'_') {
1700 		id_name[id_idx++] = c;
1701 		id_name[id_idx] = 0;
1702 	} else {
1703 		id_idx = 0;
1704 		id_name[id_idx] = 0;
1705 	}
1706 	goto loop;
1707 }
1708 
1709 static void
1710 lhsfill(wchar_t *s)	/* new rule, dump old (if exists), restart strings */
1711 {
1712 	static int lhs_len = LHS_TEXT_LEN;
1713 	int s_lhs = wslen(s);
1714 	if (s_lhs >= lhs_len) {
1715 		lhs_len = s_lhs + 2;
1716 		lhstext = (wchar_t *)
1717 		    realloc((char *)lhstext, sizeof (wchar_t)*lhs_len);
1718 		if (lhstext == NULL)
1719 /*
1720  * TRANSLATION_NOTE  -- This is a message from yacc.
1721  *	This message is passed to error() function.
1722  *	LHS -- Left Hand Side.
1723  */
1724 			error(gettext(
1725 			    "couldn't expanded LHS length"));
1726 	}
1727 	rhsfill((wchar_t *)0);
1728 	(void) wscpy(lhstext, s); /* don't worry about too long of a name */
1729 }
1730 
1731 static void
1732 rhsfill(wchar_t *s)	/* either name or 0 */
1733 {
1734 	static wchar_t *loc;	/* next free location in rhstext */
1735 	static int rhs_len = RHS_TEXT_LEN;
1736 	static int used = 0;
1737 	int s_rhs = (s == NULL ? 0 : wslen(s));
1738 	register wchar_t *p;
1739 
1740 	if (!s)	/* print out and erase old text */
1741 	{
1742 		if (*lhstext)		/* there was an old rule - dump it */
1743 			lrprnt();
1744 		(loc = rhstext)[0] = 0;
1745 		return;
1746 	}
1747 	/* add to stuff in rhstext */
1748 	p = s;
1749 
1750 	used = loc - rhstext;
1751 	if ((s_rhs + 3) >= (rhs_len - used)) {
1752 		static wchar_t *textbase;
1753 		textbase = rhstext;
1754 		rhs_len += s_rhs + RHS_TEXT_LEN;
1755 		rhstext = (wchar_t *)
1756 		    realloc((char *)rhstext, sizeof (wchar_t)*rhs_len);
1757 		if (rhstext == NULL)
1758 /*
1759  * TRANSLATION_NOTE  -- This is a message from yacc.
1760  *	This message is passed to error() function.
1761  *	RHS -- Right Hand Side.
1762  */
1763 			error(gettext(
1764 			    "couldn't expanded RHS length"));
1765 		loc = loc - textbase + rhstext;
1766 	}
1767 
1768 	*loc++ = L' ';
1769 	if (*s == L' ') /* special quoted symbol */
1770 	{
1771 		*loc++ = L'\'';	/* add first quote */
1772 		p++;
1773 	}
1774 	while ((*loc = *p++))
1775 		if (loc++ > &rhstext[ RHS_TEXT_LEN ] - 3)
1776 			break;
1777 
1778 	if (*s == L' ')
1779 		*loc++ = L'\'';
1780 	*loc = 0;		/* terminate the string */
1781 }
1782 
1783 static void
1784 lrprnt(void)	/* print out the left and right hand sides */
1785 {
1786 	wchar_t *rhs;
1787 	wchar_t *m_rhs = NULL;
1788 
1789 	if (!*rhstext)		/* empty rhs - print usual comment */
1790 		rhs = L" /* empty */";
1791 	else {
1792 		int idx1; /* tmp idx used to find if there are d_quotes */
1793 		int idx2; /* tmp idx used to generate escaped string */
1794 		wchar_t *p;
1795 		/*
1796 		 * Check if there are any double quote in RHS.
1797 		 */
1798 		for (idx1 = 0; rhstext[idx1] != 0; idx1++) {
1799 			if (rhstext[idx1] == L'"') {
1800 				/*
1801 				 * A double quote is found.
1802 				 */
1803 				idx2 = wslen(rhstext)*2;
1804 				p = m_rhs = (wchar_t *)
1805 				    malloc((idx2 + 1)*sizeof (wchar_t));
1806 				if (m_rhs == NULL)
1807 /*
1808  * TRANSLATION_NOTE  -- This is a message from yacc.
1809  *	This message is passed to error() function.
1810  *	RHS - Right Hand Side.
1811  *
1812  *	You may just translate this as:
1813  *	'Could not allocate internally used memory.'
1814  */
1815 					error(gettext(
1816 					"Couldn't allocate memory for RHS."));
1817 				/*
1818 				 * Copy string
1819 				 */
1820 				for (idx2 = 0; rhstext[idx2] != 0; idx2++) {
1821 					/*
1822 					 * Check if this quote is escaped or not
1823 					 */
1824 					if (rhstext[idx2] == L'"') {
1825 						int tmp_l = idx2-1;
1826 						int cnt = 0;
1827 						while (tmp_l >= 0 &&
1828 						    rhstext[tmp_l] == '\\') {
1829 							cnt++;
1830 							tmp_l--;
1831 						}
1832 						/*
1833 						 * If quote is not escaped,
1834 						 * then escape it.
1835 						 */
1836 						if (cnt%2 == 0)
1837 							*p++ = L'\\';
1838 					}
1839 					*p++ = rhstext[idx2];
1840 				}
1841 				*p = 0;
1842 				/*
1843 				 * Break from the loop
1844 				 */
1845 				break;
1846 			}
1847 		}
1848 		if (m_rhs == NULL)
1849 			rhs = rhstext;
1850 		else
1851 			rhs = m_rhs;
1852 	}
1853 	(void) fprintf(fdebug, WSFMT("\t\"%ws :%ws\",\n"), lhstext, rhs);
1854 	if (m_rhs)
1855 		free(m_rhs);
1856 }
1857 
1858 
1859 static void
1860 beg_debug(void)	/* dump initial sequence for fdebug file */
1861 {
1862 	(void) fprintf(fdebug,
1863 	    "typedef struct\n");
1864 	(void) fprintf(fdebug,
1865 	    "#ifdef __cplusplus\n\tyytoktype\n");
1866 	(void) fprintf(fdebug, "#endif\n{\n");
1867 	(void) fprintf(fdebug,
1868 	    "#ifdef __cplusplus\nconst\n#endif\n");
1869 	(void) fprintf(fdebug, "char *t_name; int t_val; } yytoktype;\n");
1870 	(void) fprintf(fdebug,
1871 	    "#ifndef YYDEBUG\n#\tdefine YYDEBUG\t%d", gen_testing);
1872 	(void) fprintf(fdebug, "\t/*%sallow debugging */\n#endif\n\n",
1873 	    gen_testing ? " " : " don't ");
1874 	(void) fprintf(fdebug, "#if YYDEBUG\n\nyytoktype yytoks[] =\n{\n");
1875 }
1876 
1877 
1878 static void
1879 end_toks(void)	/* finish yytoks array, get ready for yyred's strings */
1880 {
1881 	(void) fprintf(fdebug, "\t\"-unknown-\",\t-1\t/* ends search */\n");
1882 	(void) fprintf(fdebug, "};\n\n");
1883 	(void) fprintf(fdebug,
1884 	    "#ifdef __cplusplus\nconst\n#endif\n");
1885 	(void) fprintf(fdebug, "char * yyreds[] =\n{\n");
1886 	(void) fprintf(fdebug, "\t\"-no such reduction-\",\n");
1887 }
1888 
1889 
1890 static void
1891 end_debug(void)	/* finish yyred array, close file */
1892 {
1893 	lrprnt();		/* dump last lhs, rhs */
1894 	(void) fprintf(fdebug, "};\n#endif /* YYDEBUG */\n");
1895 	(void) fclose(fdebug);
1896 }
1897 
1898 
1899 /*
1900  * 2/29/88 -
1901  * The normal length for token sizes is NAMESIZE - If a token is
1902  * seen that has a longer length, expand "tokname" by NAMESIZE.
1903  */
1904 static void
1905 exp_tokname(void)
1906 {
1907 	toksize += NAMESIZE;
1908 	tokname = (wchar_t *)
1909 	    realloc((char *)tokname, sizeof (wchar_t) * toksize);
1910 }
1911 
1912 
1913 /*
1914  * 2/29/88 -
1915  *
1916  */
1917 static void
1918 exp_prod(void)
1919 {
1920 	int i;
1921 	nprodsz += NPROD;
1922 
1923 	prdptr = (int **) realloc((char *)prdptr, sizeof (int *) * (nprodsz+2));
1924 	levprd  = (int *)  realloc((char *)levprd, sizeof (int) * (nprodsz+2));
1925 	had_act = (wchar_t *)
1926 	    realloc((char *)had_act, sizeof (wchar_t) * (nprodsz+2));
1927 	for (i = nprodsz-NPROD; i < nprodsz+2; ++i)
1928 		had_act[i] = 0;
1929 
1930 	if ((*prdptr == NULL) || (levprd == NULL) || (had_act == NULL))
1931 /*
1932  * TRANSLATION_NOTE  -- This is a message from yacc.
1933  *	This message is passed to error() function.
1934  *
1935  *	You may just translate this as:
1936  *	'Could not allocate internally used memory.'
1937  */
1938 		error(gettext(
1939 		"couldn't expand productions"));
1940 }
1941 
1942 /*
1943  * 2/29/88 -
1944  * Expand the number of terminals.  Initially there are NTERMS;
1945  * each time space runs out, the size is increased by NTERMS.
1946  * The total size, however, cannot exceed MAXTERMS because of
1947  * the way LOOKSETS(struct looksets) is set up.
1948  * Tables affected:
1949  *	tokset, toklev : increased to ntoksz
1950  *
1951  *	tables with initial dimensions of TEMPSIZE must be changed if
1952  *	(ntoksz + NNONTERM) >= TEMPSIZE : temp1[]
1953  */
1954 static void
1955 exp_ntok(void)
1956 {
1957 	ntoksz += NTERMS;
1958 
1959 	tokset = (TOKSYMB *) realloc((char *)tokset, sizeof (TOKSYMB) * ntoksz);
1960 	toklev = (int *) realloc((char *)toklev, sizeof (int) * ntoksz);
1961 
1962 	if ((tokset == NULL) || (toklev == NULL))
1963 /*
1964  * TRANSLATION_NOTE  -- This is a message from yacc.
1965  *	This message is passed to error() function.
1966  *	Do not translate NTERMS.
1967  *
1968  *	You may just translate this as:
1969  *	'Could not allocate internally used memory.'
1970  */
1971 		error(gettext(
1972 		"couldn't expand NTERMS"));
1973 }
1974 
1975 
1976 static void
1977 exp_nonterm(void)
1978 {
1979 	nnontersz += NNONTERM;
1980 
1981 	nontrst = (NTSYMB *)
1982 	    realloc((char *)nontrst, sizeof (TOKSYMB) * nnontersz);
1983 	if (nontrst == NULL)
1984 /*
1985  * TRANSLATION_NOTE  -- This is a message from yacc.
1986  *	This message is passed to error() function.
1987  *	Do not translate NTERMS.
1988  *
1989  *	You may just translate this as:
1990  *	'Could not allocate internally used memory.'
1991  */
1992 		error(gettext(
1993 		"couldn't expand NNONTERM"));
1994 }
1995 
1996 void
1997 exp_mem(int flag)
1998 {
1999 	int i;
2000 	static int *membase;
2001 	new_memsize += MEMSIZE;
2002 
2003 	membase = tracemem;
2004 	tracemem = (int *)
2005 	    realloc((char *)tracemem, sizeof (int) * new_memsize);
2006 	if (tracemem == NULL)
2007 /*
2008  * TRANSLATION_NOTE  -- This is a message from yacc.
2009  *	This message is passed to error() function.
2010  *
2011  *	You may just translate this as:
2012  *	'Could not allocate internally used memory.'
2013  */
2014 		error(gettext(
2015 		    "couldn't expand mem table"));
2016 	if (flag) {
2017 		for (i = 0; i <= nprod; ++i)
2018 			prdptr[i] = prdptr[i] - membase + tracemem;
2019 		mem = mem - membase + tracemem;
2020 	} else {
2021 		size += MEMSIZE;
2022 		temp1 = (int *)realloc((char *)temp1, sizeof (int)*size);
2023 		optimmem = optimmem - membase + tracemem;
2024 	}
2025 }
2026 
2027 /*
2028  * findchtok(chlit) returns the token number for a character literal
2029  * chlit that is "bigger" than 255 -- the max char value that the
2030  * original yacc was build for.  This yacc treate them as though
2031  * an ordinary token.
2032  */
2033 static int
2034 findchtok(int chlit)
2035 {
2036 	int	i;
2037 
2038 	if (chlit < 0xff)
2039 		return (chlit); /* single-byte char */
2040 	for (i = 0; i < nmbchars; ++i) {
2041 		if (mbchars->character == chlit)
2042 			return (mbchars->tvalue);
2043 	}
2044 
2045 	/* Not found.  Register it! */
2046 	if (++nmbchars > nmbcharsz) { /* Make sure there's enough space */
2047 		nmbcharsz += NMBCHARSZ;
2048 		mbchars = (MBCLIT *)
2049 		    realloc((char *)mbchars, sizeof (MBCLIT)*nmbcharsz);
2050 		if (mbchars == NULL)
2051 			error(gettext(
2052 			"too many character literals"));
2053 	}
2054 	mbchars[nmbchars-1].character = chlit;
2055 	return (mbchars[nmbchars-1].tvalue = extval++);
2056 	/* Return the newly assigned token. */
2057 }
2058 
2059 /*
2060  * When -p is specified, symbol prefix for
2061  *	yy{parse, lex, error}(),
2062  *	yy{lval, val, char, debug, errflag, nerrs}
2063  * are defined to the specified name.
2064  */
2065 static void
2066 put_prefix_define(char *pre)
2067 {
2068 	char *syms[] = {
2069 		/* Functions */
2070 		"parse",
2071 		"lex",
2072 		"error",
2073 		/* Variables */
2074 		"lval",
2075 		"val",
2076 		"char",
2077 		"debug",
2078 		"errflag",
2079 		"nerrs",
2080 		NULL};
2081 	int i;
2082 
2083 	for (i = 0; syms[i]; i++)
2084 		(void) fprintf(ftable, "#define\tyy%s\t%s%s\n",
2085 		    syms[i], pre, syms[i]);
2086 }
2087