plural_parser.c revision 7257d1b4d25bfac0c802847390e98a464fd787ac
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 */
44static 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
79static 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
88static void	freeexpr(struct expr *);
89
90static struct expr *
91stack_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
110static struct expr *
111stack_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
134static void
135freeexpr(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
161static struct expr *
162setop1(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
188static struct expr *
189setop_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
245static int
246reduce(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
327static unsigned int
328gettoken(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 */
454int
455plural_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
640printf("========================= 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);
671exp_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
706printf("========================== 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
799printf("======================= 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
850unsigned int
851plural_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