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