xref: /illumos-gate/usr/src/lib/libc/port/i18n/plural_parser.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "lint.h"
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include "libc.h"
34 #include "gettext.h"
35 
36 #include "plural_parser.h"
37 
38 /*
39  * 31   28    24    20    16    12     8     4     0
40  * +-----+-----+-----+-----+-----+-----+-----+-----+
41  * |opnum| priority  |        operator             |
42  * +-----+-----+-----+-----+-----+-----+-----+-----+
43  */
44 static const unsigned int	operator[] = {
45 	0x00000000,		/* NULL */
46 	0x00000001,		/* INIT */
47 	0x00100002,		/* EXP */
48 	0x00200003,		/* NUM */
49 	0x00300004,		/* VAR */
50 	0x30400005,		/* CONDC */
51 	0x30500006,		/* CONDQ */
52 	0x20600007,		/* OR */
53 	0x20700008,		/* AND */
54 	0x20800009,		/* EQ */
55 	0x2080000a,		/* NEQ */
56 	0x2090000b,		/* GT */
57 	0x2090000c,		/* LT */
58 	0x2090000d,		/* GE */
59 	0x2090000e,		/* LE */
60 	0x20a0000f,		/* ADD */
61 	0x20a00010,		/* SUB */
62 	0x20b00011,		/* MUL */
63 	0x20b00012,		/* DIV */
64 	0x20b00013,		/* MOD */
65 	0x10c00014,		/* NOT */
66 	0x00d00015,		/* LPAR */
67 	0x00e00016,		/* RPAR */
68 	0x00000017		/* ERR */
69 };
70 
71 #define	STACKFREE \
72 	{ \
73 		while (stk->index > 0) \
74 			freeexpr(stk->ptr[--stk->index]); \
75 		free(stk->ptr); \
76 	}
77 
78 #ifdef	PARSE_DEBUG
79 static const char	*type_name[] = {
80 	"T_NULL",
81 	"T_INIT", "T_EXP",	"T_NUM", "T_VAR", "T_CONDC", "T_CONDQ",
82 	"T_LOR", "T_LAND", "T_EQ", "T_NEQ", "T_GT", "T_LT", "T_GE", "T_LE",
83 	"T_ADD", "T_SUB", "T_MUL", "T_DIV", "T_MOD", "T_LNOT", "T_LPAR",
84 	"T_RPAR", "T_ERR"
85 };
86 #endif
87 
88 static void	freeexpr(struct expr *);
89 
90 static struct expr *
91 stack_push(struct stack *stk, struct expr *exp)
92 {
93 #ifdef	PARSE_DEBUG
94 	printf("--- stack_push ---\n");
95 	printf("   type: %s\n", type_name[GETTYPE(exp->op)]);
96 	printf("   flag: %s\n", type_name[GETTYPE(exp->flag)]);
97 	printf("------------------\n");
98 #endif
99 	stk->ptr[stk->index++] = exp;
100 	if (stk->index == MAX_STACK_SIZE) {
101 		/* overflow */
102 		freeexpr(exp);
103 		STACKFREE;
104 		return (NULL);
105 	}
106 
107 	return (exp);
108 }
109 
110 static struct expr *
111 stack_pop(struct stack *stk,
112 	struct expr *exp_a, struct expr *exp_b)
113 {
114 	if (stk->index == 0) {
115 		/* no item */
116 		if (exp_a)
117 			freeexpr(exp_a);
118 		if (exp_b)
119 			freeexpr(exp_b);
120 		STACKFREE;
121 		return (NULL);
122 	}
123 #ifdef	PARSE_DEBUG
124 	printf("--- stack_pop ---\n");
125 	printf("   type: %s\n",
126 		type_name[GETTYPE((stk->ptr[stk->index - 1])->op)]);
127 	printf("   flag: %s\n",
128 		type_name[GETTYPE((stk->ptr[stk->index - 1])->flag)]);
129 	printf("-----------------\n");
130 #endif
131 	return (stk->ptr[--stk->index]);
132 }
133 
134 static void
135 freeexpr(struct expr *e)
136 {
137 #ifdef	PARSE_DEBUG
138 	printf("--- freeexpr ---\n");
139 	printf("   type: %s\n", type_name[GETTYPE(e->op)]);
140 	printf("----------------\n");
141 #endif
142 	switch (GETOPNUM(e->op)) {
143 	case TRINARY:
144 		if (e->nodes[2])
145 			freeexpr(e->nodes[2]);
146 		/* FALLTHROUGH */
147 	case BINARY:
148 		if (e->nodes[1])
149 			freeexpr(e->nodes[1]);
150 		/* FALLTHROUGH */
151 	case UNARY:
152 		if (e->nodes[0])
153 			freeexpr(e->nodes[0]);
154 		/* FALLTHROUGH */
155 	default:
156 		break;
157 	}
158 	free(e);
159 }
160 
161 static struct expr *
162 setop1(unsigned int op, unsigned int num,
163 	struct stack *stk, unsigned int flag)
164 {
165 	struct expr	*newitem;
166 	unsigned int	type;
167 
168 	type = GETTYPE(op);
169 
170 #ifdef	PARSE_DEBUG
171 	printf("---setop1---\n");
172 	printf("   op type: %s\n", type_name[type]);
173 	printf("-----------\n");
174 #endif
175 
176 	newitem = (struct expr *)calloc(1, sizeof (struct expr));
177 	if (!newitem) {
178 		STACKFREE;
179 		return (NULL);
180 	}
181 	newitem->op = op;
182 	if (type == T_NUM)
183 		newitem->num = num;
184 	newitem->flag = flag;
185 	return (newitem);
186 }
187 
188 static struct expr *
189 setop_reduce(unsigned int n, unsigned int op, struct stack *stk,
190 	struct expr *exp1, struct expr *exp2, struct expr *exp3)
191 {
192 	struct expr	*newitem;
193 #ifdef	PARSE_DEBUG
194 	unsigned int	type;
195 
196 	type = GETTYPE(op);
197 	printf("---setop_reduce---\n");
198 	printf("   n: %d\n", n);
199 	printf("   op type: %s\n", type_name[type]);
200 	switch (n) {
201 	case TRINARY:
202 		printf("   exp3 type: %s\n",
203 			type_name[GETTYPE(exp3->op)]);
204 	case BINARY:
205 		printf("   exp2 type: %s\n",
206 			type_name[GETTYPE(exp2->op)]);
207 	case UNARY:
208 		printf("   exp1 type: %s\n",
209 			type_name[GETTYPE(exp1->op)]);
210 	case NARY:
211 		break;
212 	}
213 	printf("-----------\n");
214 #endif
215 
216 	newitem = (struct expr *)calloc(1, sizeof (struct expr));
217 	if (!newitem) {
218 		if (exp1)
219 			freeexpr(exp1);
220 		if (exp2)
221 			freeexpr(exp2);
222 		if (exp3)
223 			freeexpr(exp3);
224 		STACKFREE;
225 		return (NULL);
226 	}
227 	newitem->op = op;
228 
229 	switch (n) {
230 	case TRINARY:
231 		newitem->nodes[2] = exp3;
232 		/* FALLTHROUGH */
233 	case BINARY:
234 		newitem->nodes[1] = exp2;
235 		/* FALLTHROUGH */
236 	case UNARY:
237 		newitem->nodes[0] = exp1;
238 		/* FALLTHROUGH */
239 	case NARY:
240 		break;
241 	}
242 	return (newitem);
243 }
244 
245 static int
246 reduce(struct expr **nexp, unsigned int n, struct expr *exp, struct stack *stk)
247 {
248 	struct expr	*exp_op, *exp1, *exp2, *exp3;
249 	unsigned int	tmp_flag;
250 	unsigned int	oop;
251 #ifdef	PARSE_DEBUG
252 	printf("---reduce---\n");
253 	printf("   n: %d\n", n);
254 	printf("-----------\n");
255 #endif
256 
257 	switch (n) {
258 	case UNARY:
259 		/* unary operator */
260 		exp1 = exp;
261 		exp_op = stack_pop(stk, exp1, NULL);
262 		if (!exp_op)
263 			return (1);
264 		tmp_flag = exp_op->flag;
265 		oop = exp_op->op;
266 		freeexpr(exp_op);
267 		*nexp = setop_reduce(UNARY, oop, stk, exp1, NULL, NULL);
268 		if (!*nexp)
269 			return (-1);
270 		(*nexp)->flag = tmp_flag;
271 		return (0);
272 	case BINARY:
273 		/* binary operator */
274 		exp2 = exp;
275 		exp_op = stack_pop(stk, exp2, NULL);
276 		if (!exp_op)
277 			return (1);
278 		exp1 = stack_pop(stk, exp_op, exp2);
279 		if (!exp1)
280 			return (1);
281 		tmp_flag = exp1->flag;
282 		oop = exp_op->op;
283 		freeexpr(exp_op);
284 		*nexp = setop_reduce(BINARY, oop, stk, exp1, exp2, NULL);
285 		if (!*nexp)
286 			return (-1);
287 		(*nexp)->flag = tmp_flag;
288 		return (0);
289 	case TRINARY:
290 		/* trinary operator: conditional */
291 		exp3 = exp;
292 		exp_op = stack_pop(stk, exp3, NULL);
293 		if (!exp_op)
294 			return (1);
295 		freeexpr(exp_op);
296 		exp2 = stack_pop(stk, exp3, NULL);
297 		if (!exp2)
298 			return (1);
299 		exp_op = stack_pop(stk, exp2, exp3);
300 		if (!exp_op)
301 			return (1);
302 		if (GETTYPE(exp_op->op) != T_CONDQ) {
303 			/* parse failed */
304 			freeexpr(exp_op);
305 			freeexpr(exp2);
306 			freeexpr(exp3);
307 			STACKFREE;
308 			return (1);
309 		}
310 		oop = exp_op->op;
311 		freeexpr(exp_op);
312 		exp1 = stack_pop(stk, exp2, exp3);
313 		if (!exp1)
314 			return (1);
315 
316 		tmp_flag = exp1->flag;
317 		*nexp = setop_reduce(TRINARY, oop, stk, exp1, exp2, exp3);
318 		if (!*nexp)
319 			return (-1);
320 		(*nexp)->flag = tmp_flag;
321 		return (0);
322 	}
323 	/* NOTREACHED */
324 	return (0);	/* keep gcc happy */
325 }
326 
327 static unsigned int
328 gettoken(const char **pstr, unsigned int *num, int which)
329 {
330 	unsigned char	*sp = *(unsigned char **)pstr;
331 	unsigned int	n;
332 	unsigned int	ret;
333 
334 	while (*sp && ((*sp == ' ') || (*sp == '\t')))
335 		sp++;
336 	if (!*sp) {
337 		if (which == GET_TOKEN)
338 			*pstr = (const char *)sp;
339 		return (T_NULL);
340 	}
341 
342 	if (isdigit(*sp)) {
343 		n = *sp - '0';
344 		sp++;
345 		while (isdigit(*sp)) {
346 			n *= 10;
347 			n += *sp - '0';
348 			sp++;
349 		}
350 		*num = n;
351 		ret = T_NUM;
352 	} else if (*sp == 'n') {
353 		sp++;
354 		ret = T_VAR;
355 	} else if (*sp == '(') {
356 		sp++;
357 		ret = T_LPAR;
358 	} else if (*sp == ')') {
359 		sp++;
360 		ret = T_RPAR;
361 	} else if (*sp == '!') {
362 		sp++;
363 		if (*sp == '=') {
364 			sp++;
365 			ret = T_NEQ;
366 		} else {
367 			ret = T_LNOT;
368 		}
369 	} else if (*sp == '*') {
370 		sp++;
371 		ret = T_MUL;
372 	} else if (*sp == '/') {
373 		sp++;
374 		ret = T_DIV;
375 	} else if (*sp == '%') {
376 		sp++;
377 		ret = T_MOD;
378 	} else if (*sp == '+') {
379 		sp++;
380 		ret = T_ADD;
381 	} else if (*sp == '-') {
382 		sp++;
383 		ret = T_SUB;
384 	} else if (*sp == '<') {
385 		sp++;
386 		if (*sp == '=') {
387 			sp++;
388 			ret = T_LE;
389 		} else {
390 			ret = T_LT;
391 		}
392 	} else if (*sp == '>') {
393 		sp++;
394 		if (*sp == '=') {
395 			sp++;
396 			ret = T_GE;
397 		} else {
398 			ret = T_GT;
399 		}
400 	} else if (*sp == '=') {
401 		sp++;
402 		if (*sp == '=') {
403 			sp++;
404 			ret = T_EQ;
405 		} else {
406 			ret = T_ERR;
407 		}
408 	} else if (*sp == '&') {
409 		sp++;
410 		if (*sp == '&') {
411 			sp++;
412 			ret = T_LAND;
413 		} else {
414 			ret = T_ERR;
415 		}
416 	} else if (*sp == '|') {
417 		sp++;
418 		if (*sp == '|') {
419 			sp++;
420 			ret = T_LOR;
421 		} else {
422 			ret = T_ERR;
423 		}
424 	} else if (*sp == '?') {
425 		sp++;
426 		ret = T_CONDQ;
427 	} else if (*sp == ':') {
428 		sp++;
429 		ret = T_CONDC;
430 	} else if ((*sp == '\n') || (*sp == ';')) {
431 		ret = T_NULL;
432 	} else {
433 		ret = T_ERR;
434 	}
435 	if (which == GET_TOKEN)
436 		*pstr = (const char *)sp;
437 	return (operator[ret]);
438 }
439 
440 /*
441  * plural_expr
442  *
443  * INPUT
444  * str: string to parse
445  *
446  * OUTPUT
447  * e: parsed expression
448  *
449  * RETURN
450  * -1: Error happend (malloc failed)
451  *  1: Parse failed (invalid expression)
452  *  0: Parse succeeded
453  */
454 int
455 plural_expr(struct expr **e, const char *plural_string)
456 {
457 	const char	*pstr = plural_string;
458 	struct stack	*stk, stkbuf;
459 	struct expr	*exp, *nexp, *exp_op, *ret;
460 	int	par, result;
461 	unsigned int	flag, ftype, fprio, fopnum, tmp_flag;
462 	unsigned int	ntype, nprio, ptype, popnum;
463 	unsigned int	op, nop, num, type, opnum;
464 
465 	stk = &stkbuf;
466 	stk->index = 0;
467 	stk->ptr = (struct expr **)malloc(
468 		sizeof (struct expr *) * MAX_STACK_SIZE);
469 	if (!stk->ptr) {
470 		/* malloc failed */
471 		return (-1);
472 	}
473 
474 	flag = operator[T_INIT];
475 	par = 0;
476 	while ((op = gettoken(&pstr, &num, GET_TOKEN)) != T_NULL) {
477 		type = GETTYPE(op);
478 		opnum = GETOPNUM(op);
479 		ftype = GETTYPE(flag);
480 
481 #ifdef	PARSE_DEBUG
482 		printf("*** %s ***\n", type_name[type]);
483 		printf("   flag: %s\n", type_name[ftype]);
484 		printf("   par: %d\n", par);
485 		printf("***********\n");
486 #endif
487 		if (type == T_ERR) {
488 			/* parse failed */
489 			STACKFREE;
490 			return (1);
491 		}
492 		if (opnum == BINARY) {
493 			/* binary operation */
494 			if (ftype != T_EXP) {
495 				/* parse failed */
496 #ifdef	PARSE_DEBUG
497 				printf("ERR: T_EXP is not followed by %s\n",
498 					type_name[type]);
499 #endif
500 				STACKFREE;
501 				return (1);
502 			}
503 			exp = setop1(op, 0, stk, flag);
504 			if (!exp)
505 				return (-1);
506 			ret = stack_push(stk, exp);
507 			if (!ret)
508 				return (1);
509 			flag = op;
510 			continue;			/* while-loop */
511 		}
512 
513 		if (type == T_CONDQ) {
514 			/* conditional operation: '?' */
515 			if (ftype != T_EXP) {
516 				/* parse failed */
517 #ifdef	PARSE_DEBUG
518 				printf("ERR: T_EXP is not followed by %s\n",
519 					type_name[type]);
520 #endif
521 				STACKFREE;
522 				return (1);
523 			}
524 			exp = setop1(op, 0, stk, flag);
525 			if (!exp)
526 				return (-1);
527 			ret = stack_push(stk, exp);
528 			if (!ret)
529 				return (1);
530 			flag = op;
531 			continue;			/* while-loop */
532 		}
533 		if (type == T_CONDC) {
534 			/* conditional operation: ':' */
535 			if (ftype != T_EXP) {
536 				/* parse failed */
537 #ifdef	PARSE_DEBUG
538 				printf("ERR: T_EXP is not followed by %s\n",
539 					type_name[type]);
540 #endif
541 				STACKFREE;
542 				return (1);
543 			}
544 			exp = setop1(op, 0, stk, flag);
545 			if (!exp)
546 				return (-1);
547 			ret = stack_push(stk, exp);
548 			if (!ret)
549 				return (1);
550 			flag = op;
551 			continue;			/* while-loop */
552 		}
553 
554 		if (type == T_LPAR) {
555 			/* left parenthesis */
556 			if (ftype == T_EXP) {
557 				/* parse failed */
558 #ifdef	PARSE_DEBUG
559 				printf("ERR: T_EXP is followed by %s\n",
560 					type_name[type]);
561 #endif
562 				STACKFREE;
563 				return (1);
564 			}
565 			exp = setop1(op, 0, stk, flag);
566 			if (!exp)
567 				return (-1);
568 			ret = stack_push(stk, exp);
569 			if (!ret)
570 				return (1);
571 			par++;
572 			flag = op;
573 			continue;			/* while-loop */
574 		}
575 		if (type == T_RPAR) {
576 			/* right parenthesis */
577 			if (ftype != T_EXP) {
578 				/* parse failed */
579 #ifdef	PARSE_DEBUG
580 				printf("ERR: T_EXP is not followed by %s\n",
581 					type_name[type]);
582 #endif
583 				STACKFREE;
584 				return (1);
585 			}
586 			par--;
587 			if (par < 0) {
588 				/* parse failed */
589 #ifdef	PARSE_DEBUG
590 				printf("ERR: too much T_RPAR\n");
591 #endif
592 				STACKFREE;
593 				return (1);
594 			}
595 			exp = stack_pop(stk, NULL, NULL);
596 			if (!exp)
597 				return (1);
598 
599 #ifdef	PARSE_DEBUG
600 			printf("======================== RPAR for loop in\n");
601 #endif
602 			for (; ; ) {
603 				ptype = GETTYPE(exp->flag);
604 				popnum = GETOPNUM(exp->flag);
605 
606 #ifdef	PARSE_DEBUG
607 				printf("=========== exp->flag: %s\n",
608 					type_name[ptype]);
609 #endif
610 				if (ptype == T_LPAR) {
611 					exp_op = stack_pop(stk, exp, NULL);
612 					if (!exp_op)
613 						return (1);
614 
615 					tmp_flag = exp_op->flag;
616 					freeexpr(exp_op);
617 
618 					exp->flag = tmp_flag;
619 					flag = tmp_flag;
620 					break;	/* break from for-loop */
621 				}
622 
623 				if ((popnum == BINARY) ||
624 					(ptype == T_LNOT) ||
625 					(ptype == T_CONDC)) {
626 					result = reduce(&nexp, popnum,
627 						exp, stk);
628 					if (result)
629 						return (result);
630 					exp = nexp;
631 					continue;	/* for-loop */
632 				}
633 				/* parse failed */
634 				freeexpr(exp);
635 				STACKFREE;
636 				return (1);
637 			} 		/* for-loop */
638 
639 #ifdef	PARSE_DEBUG
640 printf("========================= RPAR for loop out\n");
641 #endif
642 			/*
643 			 * Needs to check if exp can be reduced or not
644 			 */
645 			goto exp_check;
646 		}
647 
648 		if (type == T_LNOT) {
649 			if (ftype == T_EXP) {
650 				/* parse failed */
651 #ifdef	PARSE_DEBUG
652 				printf("ERR: T_EXP is followed by %s\n",
653 					type_name[type]);
654 #endif
655 				STACKFREE;
656 				return (1);
657 			}
658 			exp = setop1(op, 0, stk, flag);
659 			if (!exp)
660 				return (-1);
661 			ret = stack_push(stk, exp);
662 			if (!ret)
663 				return (1);
664 			flag = op;
665 			continue;			/* while-loop */
666 		}
667 		if ((type == T_NUM) || (type == T_VAR)) {
668 			exp = setop1(op, type == T_NUM ? num : 0, stk, flag);
669 			if (!exp)
670 				return (-1);
671 exp_check:
672 			ftype = GETTYPE(flag);
673 			if ((ftype == T_INIT) || (ftype == T_LPAR)) {
674 				/*
675 				 * if this NUM/VAR is the first EXP,
676 				 * just push this
677 				 */
678 				exp->flag = flag;
679 				ret = stack_push(stk, exp);
680 				if (!ret)
681 					return (1);
682 				flag = operator[T_EXP];
683 				continue;		/* while-loop */
684 			}
685 			if (ftype == T_EXP) {
686 				/*
687 				 * parse failed
688 				 * NUM/VAR cannot be seen just after
689 				 * T_EXP
690 				 */
691 				freeexpr(exp);
692 				STACKFREE;
693 				return (1);
694 			}
695 
696 			nop = gettoken(&pstr, &num, PEEK_TOKEN);
697 			if (nop != T_NULL) {
698 				ntype = GETTYPE(nop);
699 				nprio = GETPRIO(nop);
700 			} else {
701 				(void) gettoken(&pstr, &num, GET_TOKEN);
702 				ntype = T_INIT;
703 				nprio = 0;
704 			}
705 #ifdef	PARSE_DEBUG
706 printf("========================== T_NUM/T_VAR for loop in\n");
707 #endif
708 			for (; ; ) {
709 				ftype = GETTYPE(flag);
710 				fopnum = GETOPNUM(flag);
711 				fprio = GETPRIO(flag);
712 #ifdef	PARSE_DEBUG
713 				printf("========= flag: %s\n",
714 					type_name[ftype]);
715 #endif
716 				if ((ftype == T_INIT) || (ftype == T_LPAR)) {
717 					exp->flag = flag;
718 					ret = stack_push(stk, exp);
719 					if (!ret)
720 						return (1);
721 					flag = operator[T_EXP];
722 					break;		/* exit from for-loop */
723 				}
724 
725 				if (ftype == T_LNOT) {
726 					/* LNOT is the strongest */
727 					result = reduce(&nexp, UNARY, exp, stk);
728 					if (result)
729 						return (result);
730 					exp = nexp;
731 					flag = nexp->flag;
732 					continue;	/* for-loop */
733 				}
734 
735 				if (fopnum == BINARY) {
736 					/*
737 					 * binary operation
738 					 * T_MUL, T_ADD,  T_CMP,
739 					 * T_EQ,  T_LAND, T_LOR
740 					 */
741 					if ((ntype == T_RPAR) ||
742 						(nprio <= fprio)) {
743 						/* reduce */
744 						result = reduce(&nexp, BINARY,
745 							exp, stk);
746 						if (result)
747 							return (result);
748 						exp = nexp;
749 						flag = nexp->flag;
750 						continue; /* for-loop */
751 					}
752 					/* shift */
753 					exp->flag = flag;
754 					ret = stack_push(stk, exp);
755 					if (!ret)
756 						return (1);
757 					flag = operator[T_EXP];
758 					break;		/* exit from for loop */
759 				}
760 
761 				if (ftype == T_CONDQ) {
762 					/*
763 					 * CONDQ is the weakest
764 					 * always shift
765 					 */
766 					exp->flag = flag;
767 					ret = stack_push(stk, exp);
768 					if (!ret)
769 						return (1);
770 					flag = operator[T_EXP];
771 					break;		/* exit from for loop */
772 				}
773 				if (ftype == T_CONDC) {
774 					if (nprio <= fprio) {
775 						/* reduce */
776 						result = reduce(&nexp, TRINARY,
777 							exp, stk);
778 						if (result)
779 							return (result);
780 						exp = nexp;
781 						flag = nexp->flag;
782 						continue; /* for-loop */
783 					}
784 					/* shift */
785 					exp->flag = flag;
786 					ret = stack_push(stk, exp);
787 					if (!ret)
788 						return (1);
789 					flag = operator[T_EXP];
790 					break;		/* exit from for-loop */
791 				}
792 				/* parse failed */
793 				freeexpr(exp);
794 				STACKFREE;
795 				return (1);
796 			}
797 
798 #ifdef	PARSE_DEBUG
799 printf("======================= T_NUM/T_VAR for loop out\n");
800 #endif
801 			continue;			/* while-loop */
802 		}
803 		/* parse failed */
804 		STACKFREE;
805 		return (1);
806 	} 	/* while-loop */
807 
808 	if (GETTYPE(flag) != T_EXP) {
809 		/* parse failed */
810 #ifdef	PARSE_DEBUG
811 		printf("XXXX ERROR: flag is not T_INIT\n");
812 		printf("========= flag: %s\n", type_name[GETTYPE(flag)]);
813 #endif
814 		STACKFREE;
815 		return (1);
816 	} else {
817 		exp = stack_pop(stk, NULL, NULL);
818 		if (!exp)
819 			return (1);
820 
821 		if (GETTYPE(exp->flag) != T_INIT) {
822 			/* parse failed */
823 #ifdef	PARSE_DEBUG
824 			printf("ERR: flag for the result is not T_INIT\n");
825 			printf("      %s observed\n",
826 				type_name[GETTYPE(exp->flag)]);
827 #endif
828 			freeexpr(exp);
829 			STACKFREE;
830 			return (1);
831 		}
832 		if (stk->index > 0) {
833 			/*
834 			 * exp still remains in stack.
835 			 * parse failed
836 			 */
837 			while (nexp = stack_pop(stk, NULL, NULL))
838 				freeexpr(nexp);
839 			freeexpr(exp);
840 			return (1);
841 		}
842 
843 		/* parse succeeded */
844 		*e = exp;
845 		STACKFREE;
846 		return (0);
847 	}
848 }
849 
850 unsigned int
851 plural_eval(struct expr *exp, unsigned int n)
852 {
853 	unsigned int	e1, e2;
854 	unsigned int	type, opnum;
855 #ifdef GETTEXT_DEBUG
856 	(void) printf("*************** plural_eval(%p, %d)\n",
857 		exp, n);
858 	printexpr(exp, 0);
859 #endif
860 
861 	type = GETTYPE(exp->op);
862 	opnum = GETOPNUM(exp->op);
863 
864 	switch (opnum) {
865 	case NARY:
866 		if (type == T_NUM) {
867 			return (exp->num);
868 		} else if (type == T_VAR) {
869 			return (n);
870 		}
871 		break;
872 	case UNARY:
873 		/* T_LNOT */
874 		e1 = plural_eval(exp->nodes[0], n);
875 		return (!e1);
876 	case BINARY:
877 		e1 = plural_eval(exp->nodes[0], n);
878 		/* optimization for T_LOR and T_LAND */
879 		if (type == T_LOR) {
880 			return (e1 || plural_eval(exp->nodes[1], n));
881 		} else if (type == T_LAND) {
882 			return (e1 && plural_eval(exp->nodes[1], n));
883 		}
884 		e2 = plural_eval(exp->nodes[1], n);
885 		switch (type) {
886 		case T_EQ:
887 			return (e1 == e2);
888 		case T_NEQ:
889 			return (e1 != e2);
890 		case T_GT:
891 			return (e1 > e2);
892 		case T_LT:
893 			return (e1 < e2);
894 		case T_GE:
895 			return (e1 >= e2);
896 		case T_LE:
897 			return (e1 <= e2);
898 		case T_ADD:
899 			return (e1 + e2);
900 		case T_SUB:
901 			return (e1 - e2);
902 		case T_MUL:
903 			return (e1 * e2);
904 		case T_DIV:
905 			if (e2 != 0)
906 				return (e1 / e2);
907 			break;
908 		case T_MOD:
909 			if (e2 != 0)
910 				return (e1 % e2);
911 			break;
912 		}
913 		break;
914 	case TRINARY:
915 		/* T_CONDQ */
916 		e1 = plural_eval(exp->nodes[0], n);
917 		if (e1) {
918 			return (plural_eval(exp->nodes[1], n));
919 		} else {
920 			return (plural_eval(exp->nodes[2], n));
921 		}
922 	}
923 	/* should not be here */
924 	return (0);
925 }
926