xref: /onnv-gate/usr/src/lib/libc/port/i18n/plural_parser.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6812Sraf  * Common Development and Distribution License (the "License").
6*6812Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*6812Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
29*6812Sraf #include "lint.h"
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include "libc.h"
340Sstevel@tonic-gate #include "gettext.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include "plural_parser.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * 31   28    24    20    16    12     8     4     0
400Sstevel@tonic-gate  * +-----+-----+-----+-----+-----+-----+-----+-----+
410Sstevel@tonic-gate  * |opnum| priority  |        operator             |
420Sstevel@tonic-gate  * +-----+-----+-----+-----+-----+-----+-----+-----+
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate static const unsigned int	operator[] = {
450Sstevel@tonic-gate 	0x00000000,		/* NULL */
460Sstevel@tonic-gate 	0x00000001,		/* INIT */
470Sstevel@tonic-gate 	0x00100002,		/* EXP */
480Sstevel@tonic-gate 	0x00200003,		/* NUM */
490Sstevel@tonic-gate 	0x00300004,		/* VAR */
500Sstevel@tonic-gate 	0x30400005,		/* CONDC */
510Sstevel@tonic-gate 	0x30500006,		/* CONDQ */
520Sstevel@tonic-gate 	0x20600007,		/* OR */
530Sstevel@tonic-gate 	0x20700008,		/* AND */
540Sstevel@tonic-gate 	0x20800009,		/* EQ */
550Sstevel@tonic-gate 	0x2080000a,		/* NEQ */
560Sstevel@tonic-gate 	0x2090000b,		/* GT */
570Sstevel@tonic-gate 	0x2090000c,		/* LT */
580Sstevel@tonic-gate 	0x2090000d,		/* GE */
590Sstevel@tonic-gate 	0x2090000e,		/* LE */
600Sstevel@tonic-gate 	0x20a0000f,		/* ADD */
610Sstevel@tonic-gate 	0x20a00010,		/* SUB */
620Sstevel@tonic-gate 	0x20b00011,		/* MUL */
630Sstevel@tonic-gate 	0x20b00012,		/* DIV */
640Sstevel@tonic-gate 	0x20b00013,		/* MOD */
650Sstevel@tonic-gate 	0x10c00014,		/* NOT */
660Sstevel@tonic-gate 	0x00d00015,		/* LPAR */
670Sstevel@tonic-gate 	0x00e00016,		/* RPAR */
680Sstevel@tonic-gate 	0x00000017		/* ERR */
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	STACKFREE \
720Sstevel@tonic-gate 	{ \
730Sstevel@tonic-gate 		while (stk->index > 0) \
740Sstevel@tonic-gate 			freeexpr(stk->ptr[--stk->index]); \
750Sstevel@tonic-gate 		free(stk->ptr); \
760Sstevel@tonic-gate 	}
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #ifdef	PARSE_DEBUG
790Sstevel@tonic-gate static const char	*type_name[] = {
800Sstevel@tonic-gate 	"T_NULL",
810Sstevel@tonic-gate 	"T_INIT", "T_EXP",	"T_NUM", "T_VAR", "T_CONDC", "T_CONDQ",
820Sstevel@tonic-gate 	"T_LOR", "T_LAND", "T_EQ", "T_NEQ", "T_GT", "T_LT", "T_GE", "T_LE",
830Sstevel@tonic-gate 	"T_ADD", "T_SUB", "T_MUL", "T_DIV", "T_MOD", "T_LNOT", "T_LPAR",
840Sstevel@tonic-gate 	"T_RPAR", "T_ERR"
850Sstevel@tonic-gate };
860Sstevel@tonic-gate #endif
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static void	freeexpr(struct expr *);
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static struct expr *
stack_push(struct stack * stk,struct expr * exp)910Sstevel@tonic-gate stack_push(struct stack *stk, struct expr *exp)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate #ifdef	PARSE_DEBUG
940Sstevel@tonic-gate 	printf("--- stack_push ---\n");
950Sstevel@tonic-gate 	printf("   type: %s\n", type_name[GETTYPE(exp->op)]);
960Sstevel@tonic-gate 	printf("   flag: %s\n", type_name[GETTYPE(exp->flag)]);
970Sstevel@tonic-gate 	printf("------------------\n");
980Sstevel@tonic-gate #endif
990Sstevel@tonic-gate 	stk->ptr[stk->index++] = exp;
1000Sstevel@tonic-gate 	if (stk->index == MAX_STACK_SIZE) {
1010Sstevel@tonic-gate 		/* overflow */
1020Sstevel@tonic-gate 		freeexpr(exp);
1030Sstevel@tonic-gate 		STACKFREE;
1040Sstevel@tonic-gate 		return (NULL);
1050Sstevel@tonic-gate 	}
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	return (exp);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static struct expr *
stack_pop(struct stack * stk,struct expr * exp_a,struct expr * exp_b)1110Sstevel@tonic-gate stack_pop(struct stack *stk,
1120Sstevel@tonic-gate 	struct expr *exp_a, struct expr *exp_b)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate 	if (stk->index == 0) {
1150Sstevel@tonic-gate 		/* no item */
1160Sstevel@tonic-gate 		if (exp_a)
1170Sstevel@tonic-gate 			freeexpr(exp_a);
1180Sstevel@tonic-gate 		if (exp_b)
1190Sstevel@tonic-gate 			freeexpr(exp_b);
1200Sstevel@tonic-gate 		STACKFREE;
1210Sstevel@tonic-gate 		return (NULL);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate #ifdef	PARSE_DEBUG
1240Sstevel@tonic-gate 	printf("--- stack_pop ---\n");
1250Sstevel@tonic-gate 	printf("   type: %s\n",
1260Sstevel@tonic-gate 		type_name[GETTYPE((stk->ptr[stk->index - 1])->op)]);
1270Sstevel@tonic-gate 	printf("   flag: %s\n",
1280Sstevel@tonic-gate 		type_name[GETTYPE((stk->ptr[stk->index - 1])->flag)]);
1290Sstevel@tonic-gate 	printf("-----------------\n");
1300Sstevel@tonic-gate #endif
1310Sstevel@tonic-gate 	return (stk->ptr[--stk->index]);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate static void
freeexpr(struct expr * e)1350Sstevel@tonic-gate freeexpr(struct expr *e)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate #ifdef	PARSE_DEBUG
1380Sstevel@tonic-gate 	printf("--- freeexpr ---\n");
1390Sstevel@tonic-gate 	printf("   type: %s\n", type_name[GETTYPE(e->op)]);
1400Sstevel@tonic-gate 	printf("----------------\n");
1410Sstevel@tonic-gate #endif
1420Sstevel@tonic-gate 	switch (GETOPNUM(e->op)) {
1430Sstevel@tonic-gate 	case TRINARY:
1440Sstevel@tonic-gate 		if (e->nodes[2])
1450Sstevel@tonic-gate 			freeexpr(e->nodes[2]);
1460Sstevel@tonic-gate 		/* FALLTHROUGH */
1470Sstevel@tonic-gate 	case BINARY:
1480Sstevel@tonic-gate 		if (e->nodes[1])
1490Sstevel@tonic-gate 			freeexpr(e->nodes[1]);
1500Sstevel@tonic-gate 		/* FALLTHROUGH */
1510Sstevel@tonic-gate 	case UNARY:
1520Sstevel@tonic-gate 		if (e->nodes[0])
1530Sstevel@tonic-gate 			freeexpr(e->nodes[0]);
1540Sstevel@tonic-gate 		/* FALLTHROUGH */
1550Sstevel@tonic-gate 	default:
1560Sstevel@tonic-gate 		break;
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	free(e);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static struct expr *
setop1(unsigned int op,unsigned int num,struct stack * stk,unsigned int flag)1620Sstevel@tonic-gate setop1(unsigned int op, unsigned int num,
1630Sstevel@tonic-gate 	struct stack *stk, unsigned int flag)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	struct expr	*newitem;
1660Sstevel@tonic-gate 	unsigned int	type;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	type = GETTYPE(op);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate #ifdef	PARSE_DEBUG
1710Sstevel@tonic-gate 	printf("---setop1---\n");
1720Sstevel@tonic-gate 	printf("   op type: %s\n", type_name[type]);
1730Sstevel@tonic-gate 	printf("-----------\n");
1740Sstevel@tonic-gate #endif
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	newitem = (struct expr *)calloc(1, sizeof (struct expr));
1770Sstevel@tonic-gate 	if (!newitem) {
1780Sstevel@tonic-gate 		STACKFREE;
1790Sstevel@tonic-gate 		return (NULL);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	newitem->op = op;
1820Sstevel@tonic-gate 	if (type == T_NUM)
1830Sstevel@tonic-gate 		newitem->num = num;
1840Sstevel@tonic-gate 	newitem->flag = flag;
1850Sstevel@tonic-gate 	return (newitem);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate static struct expr *
setop_reduce(unsigned int n,unsigned int op,struct stack * stk,struct expr * exp1,struct expr * exp2,struct expr * exp3)1890Sstevel@tonic-gate setop_reduce(unsigned int n, unsigned int op, struct stack *stk,
1900Sstevel@tonic-gate 	struct expr *exp1, struct expr *exp2, struct expr *exp3)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	struct expr	*newitem;
1930Sstevel@tonic-gate #ifdef	PARSE_DEBUG
1940Sstevel@tonic-gate 	unsigned int	type;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	type = GETTYPE(op);
1970Sstevel@tonic-gate 	printf("---setop_reduce---\n");
1980Sstevel@tonic-gate 	printf("   n: %d\n", n);
1990Sstevel@tonic-gate 	printf("   op type: %s\n", type_name[type]);
2000Sstevel@tonic-gate 	switch (n) {
2010Sstevel@tonic-gate 	case TRINARY:
2020Sstevel@tonic-gate 		printf("   exp3 type: %s\n",
2030Sstevel@tonic-gate 			type_name[GETTYPE(exp3->op)]);
2040Sstevel@tonic-gate 	case BINARY:
2050Sstevel@tonic-gate 		printf("   exp2 type: %s\n",
2060Sstevel@tonic-gate 			type_name[GETTYPE(exp2->op)]);
2070Sstevel@tonic-gate 	case UNARY:
2080Sstevel@tonic-gate 		printf("   exp1 type: %s\n",
2090Sstevel@tonic-gate 			type_name[GETTYPE(exp1->op)]);
2100Sstevel@tonic-gate 	case NARY:
2110Sstevel@tonic-gate 		break;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	printf("-----------\n");
2140Sstevel@tonic-gate #endif
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	newitem = (struct expr *)calloc(1, sizeof (struct expr));
2170Sstevel@tonic-gate 	if (!newitem) {
2180Sstevel@tonic-gate 		if (exp1)
2190Sstevel@tonic-gate 			freeexpr(exp1);
2200Sstevel@tonic-gate 		if (exp2)
2210Sstevel@tonic-gate 			freeexpr(exp2);
2220Sstevel@tonic-gate 		if (exp3)
2230Sstevel@tonic-gate 			freeexpr(exp3);
2240Sstevel@tonic-gate 		STACKFREE;
2250Sstevel@tonic-gate 		return (NULL);
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 	newitem->op = op;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	switch (n) {
2300Sstevel@tonic-gate 	case TRINARY:
2310Sstevel@tonic-gate 		newitem->nodes[2] = exp3;
2320Sstevel@tonic-gate 		/* FALLTHROUGH */
2330Sstevel@tonic-gate 	case BINARY:
2340Sstevel@tonic-gate 		newitem->nodes[1] = exp2;
2350Sstevel@tonic-gate 		/* FALLTHROUGH */
2360Sstevel@tonic-gate 	case UNARY:
2370Sstevel@tonic-gate 		newitem->nodes[0] = exp1;
2380Sstevel@tonic-gate 		/* FALLTHROUGH */
2390Sstevel@tonic-gate 	case NARY:
2400Sstevel@tonic-gate 		break;
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 	return (newitem);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static int
reduce(struct expr ** nexp,unsigned int n,struct expr * exp,struct stack * stk)2460Sstevel@tonic-gate reduce(struct expr **nexp, unsigned int n, struct expr *exp, struct stack *stk)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	struct expr	*exp_op, *exp1, *exp2, *exp3;
2490Sstevel@tonic-gate 	unsigned int	tmp_flag;
2500Sstevel@tonic-gate 	unsigned int	oop;
2510Sstevel@tonic-gate #ifdef	PARSE_DEBUG
2520Sstevel@tonic-gate 	printf("---reduce---\n");
2530Sstevel@tonic-gate 	printf("   n: %d\n", n);
2540Sstevel@tonic-gate 	printf("-----------\n");
2550Sstevel@tonic-gate #endif
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	switch (n) {
2580Sstevel@tonic-gate 	case UNARY:
2590Sstevel@tonic-gate 		/* unary operator */
2600Sstevel@tonic-gate 		exp1 = exp;
2610Sstevel@tonic-gate 		exp_op = stack_pop(stk, exp1, NULL);
2620Sstevel@tonic-gate 		if (!exp_op)
2630Sstevel@tonic-gate 			return (1);
2640Sstevel@tonic-gate 		tmp_flag = exp_op->flag;
2650Sstevel@tonic-gate 		oop = exp_op->op;
2660Sstevel@tonic-gate 		freeexpr(exp_op);
2670Sstevel@tonic-gate 		*nexp = setop_reduce(UNARY, oop, stk, exp1, NULL, NULL);
2680Sstevel@tonic-gate 		if (!*nexp)
2690Sstevel@tonic-gate 			return (-1);
2700Sstevel@tonic-gate 		(*nexp)->flag = tmp_flag;
2710Sstevel@tonic-gate 		return (0);
2720Sstevel@tonic-gate 	case BINARY:
2730Sstevel@tonic-gate 		/* binary operator */
2740Sstevel@tonic-gate 		exp2 = exp;
2750Sstevel@tonic-gate 		exp_op = stack_pop(stk, exp2, NULL);
2760Sstevel@tonic-gate 		if (!exp_op)
2770Sstevel@tonic-gate 			return (1);
2780Sstevel@tonic-gate 		exp1 = stack_pop(stk, exp_op, exp2);
2790Sstevel@tonic-gate 		if (!exp1)
2800Sstevel@tonic-gate 			return (1);
2810Sstevel@tonic-gate 		tmp_flag = exp1->flag;
2820Sstevel@tonic-gate 		oop = exp_op->op;
2830Sstevel@tonic-gate 		freeexpr(exp_op);
2840Sstevel@tonic-gate 		*nexp = setop_reduce(BINARY, oop, stk, exp1, exp2, NULL);
2850Sstevel@tonic-gate 		if (!*nexp)
2860Sstevel@tonic-gate 			return (-1);
2870Sstevel@tonic-gate 		(*nexp)->flag = tmp_flag;
2880Sstevel@tonic-gate 		return (0);
2890Sstevel@tonic-gate 	case TRINARY:
2900Sstevel@tonic-gate 		/* trinary operator: conditional */
2910Sstevel@tonic-gate 		exp3 = exp;
2920Sstevel@tonic-gate 		exp_op = stack_pop(stk, exp3, NULL);
2930Sstevel@tonic-gate 		if (!exp_op)
2940Sstevel@tonic-gate 			return (1);
2950Sstevel@tonic-gate 		freeexpr(exp_op);
2960Sstevel@tonic-gate 		exp2 = stack_pop(stk, exp3, NULL);
2970Sstevel@tonic-gate 		if (!exp2)
2980Sstevel@tonic-gate 			return (1);
2990Sstevel@tonic-gate 		exp_op = stack_pop(stk, exp2, exp3);
3000Sstevel@tonic-gate 		if (!exp_op)
3010Sstevel@tonic-gate 			return (1);
3020Sstevel@tonic-gate 		if (GETTYPE(exp_op->op) != T_CONDQ) {
3030Sstevel@tonic-gate 			/* parse failed */
3040Sstevel@tonic-gate 			freeexpr(exp_op);
3050Sstevel@tonic-gate 			freeexpr(exp2);
3060Sstevel@tonic-gate 			freeexpr(exp3);
3070Sstevel@tonic-gate 			STACKFREE;
3080Sstevel@tonic-gate 			return (1);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 		oop = exp_op->op;
3110Sstevel@tonic-gate 		freeexpr(exp_op);
3120Sstevel@tonic-gate 		exp1 = stack_pop(stk, exp2, exp3);
3130Sstevel@tonic-gate 		if (!exp1)
3140Sstevel@tonic-gate 			return (1);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		tmp_flag = exp1->flag;
3170Sstevel@tonic-gate 		*nexp = setop_reduce(TRINARY, oop, stk, exp1, exp2, exp3);
3180Sstevel@tonic-gate 		if (!*nexp)
3190Sstevel@tonic-gate 			return (-1);
3200Sstevel@tonic-gate 		(*nexp)->flag = tmp_flag;
3210Sstevel@tonic-gate 		return (0);
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 	/* NOTREACHED */
3240Sstevel@tonic-gate 	return (0);	/* keep gcc happy */
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate static unsigned int
gettoken(const char ** pstr,unsigned int * num,int which)3280Sstevel@tonic-gate gettoken(const char **pstr, unsigned int *num, int which)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	unsigned char	*sp = *(unsigned char **)pstr;
3310Sstevel@tonic-gate 	unsigned int	n;
3320Sstevel@tonic-gate 	unsigned int	ret;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	while (*sp && ((*sp == ' ') || (*sp == '\t')))
3350Sstevel@tonic-gate 		sp++;
3360Sstevel@tonic-gate 	if (!*sp) {
3370Sstevel@tonic-gate 		if (which == GET_TOKEN)
3380Sstevel@tonic-gate 			*pstr = (const char *)sp;
3390Sstevel@tonic-gate 		return (T_NULL);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	if (isdigit(*sp)) {
3430Sstevel@tonic-gate 		n = *sp - '0';
3440Sstevel@tonic-gate 		sp++;
3450Sstevel@tonic-gate 		while (isdigit(*sp)) {
3460Sstevel@tonic-gate 			n *= 10;
3470Sstevel@tonic-gate 			n += *sp - '0';
3480Sstevel@tonic-gate 			sp++;
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 		*num = n;
3510Sstevel@tonic-gate 		ret = T_NUM;
3520Sstevel@tonic-gate 	} else if (*sp == 'n') {
3530Sstevel@tonic-gate 		sp++;
3540Sstevel@tonic-gate 		ret = T_VAR;
3550Sstevel@tonic-gate 	} else if (*sp == '(') {
3560Sstevel@tonic-gate 		sp++;
3570Sstevel@tonic-gate 		ret = T_LPAR;
3580Sstevel@tonic-gate 	} else if (*sp == ')') {
3590Sstevel@tonic-gate 		sp++;
3600Sstevel@tonic-gate 		ret = T_RPAR;
3610Sstevel@tonic-gate 	} else if (*sp == '!') {
3620Sstevel@tonic-gate 		sp++;
3630Sstevel@tonic-gate 		if (*sp == '=') {
3640Sstevel@tonic-gate 			sp++;
3650Sstevel@tonic-gate 			ret = T_NEQ;
3660Sstevel@tonic-gate 		} else {
3670Sstevel@tonic-gate 			ret = T_LNOT;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 	} else if (*sp == '*') {
3700Sstevel@tonic-gate 		sp++;
3710Sstevel@tonic-gate 		ret = T_MUL;
3720Sstevel@tonic-gate 	} else if (*sp == '/') {
3730Sstevel@tonic-gate 		sp++;
3740Sstevel@tonic-gate 		ret = T_DIV;
3750Sstevel@tonic-gate 	} else if (*sp == '%') {
3760Sstevel@tonic-gate 		sp++;
3770Sstevel@tonic-gate 		ret = T_MOD;
3780Sstevel@tonic-gate 	} else if (*sp == '+') {
3790Sstevel@tonic-gate 		sp++;
3800Sstevel@tonic-gate 		ret = T_ADD;
3810Sstevel@tonic-gate 	} else if (*sp == '-') {
3820Sstevel@tonic-gate 		sp++;
3830Sstevel@tonic-gate 		ret = T_SUB;
3840Sstevel@tonic-gate 	} else if (*sp == '<') {
3850Sstevel@tonic-gate 		sp++;
3860Sstevel@tonic-gate 		if (*sp == '=') {
3870Sstevel@tonic-gate 			sp++;
3880Sstevel@tonic-gate 			ret = T_LE;
3890Sstevel@tonic-gate 		} else {
3900Sstevel@tonic-gate 			ret = T_LT;
3910Sstevel@tonic-gate 		}
3920Sstevel@tonic-gate 	} else if (*sp == '>') {
3930Sstevel@tonic-gate 		sp++;
3940Sstevel@tonic-gate 		if (*sp == '=') {
3950Sstevel@tonic-gate 			sp++;
3960Sstevel@tonic-gate 			ret = T_GE;
3970Sstevel@tonic-gate 		} else {
3980Sstevel@tonic-gate 			ret = T_GT;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 	} else if (*sp == '=') {
4010Sstevel@tonic-gate 		sp++;
4020Sstevel@tonic-gate 		if (*sp == '=') {
4030Sstevel@tonic-gate 			sp++;
4040Sstevel@tonic-gate 			ret = T_EQ;
4050Sstevel@tonic-gate 		} else {
4060Sstevel@tonic-gate 			ret = T_ERR;
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 	} else if (*sp == '&') {
4090Sstevel@tonic-gate 		sp++;
4100Sstevel@tonic-gate 		if (*sp == '&') {
4110Sstevel@tonic-gate 			sp++;
4120Sstevel@tonic-gate 			ret = T_LAND;
4130Sstevel@tonic-gate 		} else {
4140Sstevel@tonic-gate 			ret = T_ERR;
4150Sstevel@tonic-gate 		}
4160Sstevel@tonic-gate 	} else if (*sp == '|') {
4170Sstevel@tonic-gate 		sp++;
4180Sstevel@tonic-gate 		if (*sp == '|') {
4190Sstevel@tonic-gate 			sp++;
4200Sstevel@tonic-gate 			ret = T_LOR;
4210Sstevel@tonic-gate 		} else {
4220Sstevel@tonic-gate 			ret = T_ERR;
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 	} else if (*sp == '?') {
4250Sstevel@tonic-gate 		sp++;
4260Sstevel@tonic-gate 		ret = T_CONDQ;
4270Sstevel@tonic-gate 	} else if (*sp == ':') {
4280Sstevel@tonic-gate 		sp++;
4290Sstevel@tonic-gate 		ret = T_CONDC;
4300Sstevel@tonic-gate 	} else if ((*sp == '\n') || (*sp == ';')) {
4310Sstevel@tonic-gate 		ret = T_NULL;
4320Sstevel@tonic-gate 	} else {
4330Sstevel@tonic-gate 		ret = T_ERR;
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	if (which == GET_TOKEN)
4360Sstevel@tonic-gate 		*pstr = (const char *)sp;
4370Sstevel@tonic-gate 	return (operator[ret]);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate  * plural_expr
4420Sstevel@tonic-gate  *
4430Sstevel@tonic-gate  * INPUT
4440Sstevel@tonic-gate  * str: string to parse
4450Sstevel@tonic-gate  *
4460Sstevel@tonic-gate  * OUTPUT
4470Sstevel@tonic-gate  * e: parsed expression
4480Sstevel@tonic-gate  *
4490Sstevel@tonic-gate  * RETURN
4500Sstevel@tonic-gate  * -1: Error happend (malloc failed)
4510Sstevel@tonic-gate  *  1: Parse failed (invalid expression)
4520Sstevel@tonic-gate  *  0: Parse succeeded
4530Sstevel@tonic-gate  */
4540Sstevel@tonic-gate int
plural_expr(struct expr ** e,const char * plural_string)4550Sstevel@tonic-gate plural_expr(struct expr **e, const char *plural_string)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	const char	*pstr = plural_string;
4580Sstevel@tonic-gate 	struct stack	*stk, stkbuf;
4590Sstevel@tonic-gate 	struct expr	*exp, *nexp, *exp_op, *ret;
4600Sstevel@tonic-gate 	int	par, result;
4610Sstevel@tonic-gate 	unsigned int	flag, ftype, fprio, fopnum, tmp_flag;
4620Sstevel@tonic-gate 	unsigned int	ntype, nprio, ptype, popnum;
4630Sstevel@tonic-gate 	unsigned int	op, nop, num, type, opnum;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	stk = &stkbuf;
4660Sstevel@tonic-gate 	stk->index = 0;
4670Sstevel@tonic-gate 	stk->ptr = (struct expr **)malloc(
4680Sstevel@tonic-gate 		sizeof (struct expr *) * MAX_STACK_SIZE);
4690Sstevel@tonic-gate 	if (!stk->ptr) {
4700Sstevel@tonic-gate 		/* malloc failed */
4710Sstevel@tonic-gate 		return (-1);
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	flag = operator[T_INIT];
4750Sstevel@tonic-gate 	par = 0;
4760Sstevel@tonic-gate 	while ((op = gettoken(&pstr, &num, GET_TOKEN)) != T_NULL) {
4770Sstevel@tonic-gate 		type = GETTYPE(op);
4780Sstevel@tonic-gate 		opnum = GETOPNUM(op);
4790Sstevel@tonic-gate 		ftype = GETTYPE(flag);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate #ifdef	PARSE_DEBUG
4820Sstevel@tonic-gate 		printf("*** %s ***\n", type_name[type]);
4830Sstevel@tonic-gate 		printf("   flag: %s\n", type_name[ftype]);
4840Sstevel@tonic-gate 		printf("   par: %d\n", par);
4850Sstevel@tonic-gate 		printf("***********\n");
4860Sstevel@tonic-gate #endif
4870Sstevel@tonic-gate 		if (type == T_ERR) {
4880Sstevel@tonic-gate 			/* parse failed */
4890Sstevel@tonic-gate 			STACKFREE;
4900Sstevel@tonic-gate 			return (1);
4910Sstevel@tonic-gate 		}
4920Sstevel@tonic-gate 		if (opnum == BINARY) {
4930Sstevel@tonic-gate 			/* binary operation */
4940Sstevel@tonic-gate 			if (ftype != T_EXP) {
4950Sstevel@tonic-gate 				/* parse failed */
4960Sstevel@tonic-gate #ifdef	PARSE_DEBUG
4970Sstevel@tonic-gate 				printf("ERR: T_EXP is not followed by %s\n",
4980Sstevel@tonic-gate 					type_name[type]);
4990Sstevel@tonic-gate #endif
5000Sstevel@tonic-gate 				STACKFREE;
5010Sstevel@tonic-gate 				return (1);
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 			exp = setop1(op, 0, stk, flag);
5040Sstevel@tonic-gate 			if (!exp)
5050Sstevel@tonic-gate 				return (-1);
5060Sstevel@tonic-gate 			ret = stack_push(stk, exp);
5070Sstevel@tonic-gate 			if (!ret)
5080Sstevel@tonic-gate 				return (1);
5090Sstevel@tonic-gate 			flag = op;
5100Sstevel@tonic-gate 			continue;			/* while-loop */
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		if (type == T_CONDQ) {
5140Sstevel@tonic-gate 			/* conditional operation: '?' */
5150Sstevel@tonic-gate 			if (ftype != T_EXP) {
5160Sstevel@tonic-gate 				/* parse failed */
5170Sstevel@tonic-gate #ifdef	PARSE_DEBUG
5180Sstevel@tonic-gate 				printf("ERR: T_EXP is not followed by %s\n",
5190Sstevel@tonic-gate 					type_name[type]);
5200Sstevel@tonic-gate #endif
5210Sstevel@tonic-gate 				STACKFREE;
5220Sstevel@tonic-gate 				return (1);
5230Sstevel@tonic-gate 			}
5240Sstevel@tonic-gate 			exp = setop1(op, 0, stk, flag);
5250Sstevel@tonic-gate 			if (!exp)
5260Sstevel@tonic-gate 				return (-1);
5270Sstevel@tonic-gate 			ret = stack_push(stk, exp);
5280Sstevel@tonic-gate 			if (!ret)
5290Sstevel@tonic-gate 				return (1);
5300Sstevel@tonic-gate 			flag = op;
5310Sstevel@tonic-gate 			continue;			/* while-loop */
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 		if (type == T_CONDC) {
5340Sstevel@tonic-gate 			/* conditional operation: ':' */
5350Sstevel@tonic-gate 			if (ftype != T_EXP) {
5360Sstevel@tonic-gate 				/* parse failed */
5370Sstevel@tonic-gate #ifdef	PARSE_DEBUG
5380Sstevel@tonic-gate 				printf("ERR: T_EXP is not followed by %s\n",
5390Sstevel@tonic-gate 					type_name[type]);
5400Sstevel@tonic-gate #endif
5410Sstevel@tonic-gate 				STACKFREE;
5420Sstevel@tonic-gate 				return (1);
5430Sstevel@tonic-gate 			}
5440Sstevel@tonic-gate 			exp = setop1(op, 0, stk, flag);
5450Sstevel@tonic-gate 			if (!exp)
5460Sstevel@tonic-gate 				return (-1);
5470Sstevel@tonic-gate 			ret = stack_push(stk, exp);
5480Sstevel@tonic-gate 			if (!ret)
5490Sstevel@tonic-gate 				return (1);
5500Sstevel@tonic-gate 			flag = op;
5510Sstevel@tonic-gate 			continue;			/* while-loop */
5520Sstevel@tonic-gate 		}
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 		if (type == T_LPAR) {
5550Sstevel@tonic-gate 			/* left parenthesis */
5560Sstevel@tonic-gate 			if (ftype == T_EXP) {
5570Sstevel@tonic-gate 				/* parse failed */
5580Sstevel@tonic-gate #ifdef	PARSE_DEBUG
5590Sstevel@tonic-gate 				printf("ERR: T_EXP is followed by %s\n",
5600Sstevel@tonic-gate 					type_name[type]);
5610Sstevel@tonic-gate #endif
5620Sstevel@tonic-gate 				STACKFREE;
5630Sstevel@tonic-gate 				return (1);
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 			exp = setop1(op, 0, stk, flag);
5660Sstevel@tonic-gate 			if (!exp)
5670Sstevel@tonic-gate 				return (-1);
5680Sstevel@tonic-gate 			ret = stack_push(stk, exp);
5690Sstevel@tonic-gate 			if (!ret)
5700Sstevel@tonic-gate 				return (1);
5710Sstevel@tonic-gate 			par++;
5720Sstevel@tonic-gate 			flag = op;
5730Sstevel@tonic-gate 			continue;			/* while-loop */
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 		if (type == T_RPAR) {
5760Sstevel@tonic-gate 			/* right parenthesis */
5770Sstevel@tonic-gate 			if (ftype != T_EXP) {
5780Sstevel@tonic-gate 				/* parse failed */
5790Sstevel@tonic-gate #ifdef	PARSE_DEBUG
5800Sstevel@tonic-gate 				printf("ERR: T_EXP is not followed by %s\n",
5810Sstevel@tonic-gate 					type_name[type]);
5820Sstevel@tonic-gate #endif
5830Sstevel@tonic-gate 				STACKFREE;
5840Sstevel@tonic-gate 				return (1);
5850Sstevel@tonic-gate 			}
5860Sstevel@tonic-gate 			par--;
5870Sstevel@tonic-gate 			if (par < 0) {
5880Sstevel@tonic-gate 				/* parse failed */
5890Sstevel@tonic-gate #ifdef	PARSE_DEBUG
5900Sstevel@tonic-gate 				printf("ERR: too much T_RPAR\n");
5910Sstevel@tonic-gate #endif
5920Sstevel@tonic-gate 				STACKFREE;
5930Sstevel@tonic-gate 				return (1);
5940Sstevel@tonic-gate 			}
5950Sstevel@tonic-gate 			exp = stack_pop(stk, NULL, NULL);
5960Sstevel@tonic-gate 			if (!exp)
5970Sstevel@tonic-gate 				return (1);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate #ifdef	PARSE_DEBUG
6000Sstevel@tonic-gate 			printf("======================== RPAR for loop in\n");
6010Sstevel@tonic-gate #endif
6020Sstevel@tonic-gate 			for (; ; ) {
6030Sstevel@tonic-gate 				ptype = GETTYPE(exp->flag);
6040Sstevel@tonic-gate 				popnum = GETOPNUM(exp->flag);
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate #ifdef	PARSE_DEBUG
6070Sstevel@tonic-gate 				printf("=========== exp->flag: %s\n",
6080Sstevel@tonic-gate 					type_name[ptype]);
6090Sstevel@tonic-gate #endif
6100Sstevel@tonic-gate 				if (ptype == T_LPAR) {
6110Sstevel@tonic-gate 					exp_op = stack_pop(stk, exp, NULL);
6120Sstevel@tonic-gate 					if (!exp_op)
6130Sstevel@tonic-gate 						return (1);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 					tmp_flag = exp_op->flag;
6160Sstevel@tonic-gate 					freeexpr(exp_op);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 					exp->flag = tmp_flag;
6190Sstevel@tonic-gate 					flag = tmp_flag;
6200Sstevel@tonic-gate 					break;	/* break from for-loop */
6210Sstevel@tonic-gate 				}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 				if ((popnum == BINARY) ||
6240Sstevel@tonic-gate 					(ptype == T_LNOT) ||
6250Sstevel@tonic-gate 					(ptype == T_CONDC)) {
6260Sstevel@tonic-gate 					result = reduce(&nexp, popnum,
6270Sstevel@tonic-gate 						exp, stk);
6280Sstevel@tonic-gate 					if (result)
6290Sstevel@tonic-gate 						return (result);
6300Sstevel@tonic-gate 					exp = nexp;
6310Sstevel@tonic-gate 					continue;	/* for-loop */
6320Sstevel@tonic-gate 				}
6330Sstevel@tonic-gate 				/* parse failed */
6340Sstevel@tonic-gate 				freeexpr(exp);
6350Sstevel@tonic-gate 				STACKFREE;
6360Sstevel@tonic-gate 				return (1);
6370Sstevel@tonic-gate 			} 		/* for-loop */
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate #ifdef	PARSE_DEBUG
6400Sstevel@tonic-gate printf("========================= RPAR for loop out\n");
6410Sstevel@tonic-gate #endif
6420Sstevel@tonic-gate 			/*
6430Sstevel@tonic-gate 			 * Needs to check if exp can be reduced or not
6440Sstevel@tonic-gate 			 */
6450Sstevel@tonic-gate 			goto exp_check;
6460Sstevel@tonic-gate 		}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		if (type == T_LNOT) {
6490Sstevel@tonic-gate 			if (ftype == T_EXP) {
6500Sstevel@tonic-gate 				/* parse failed */
6510Sstevel@tonic-gate #ifdef	PARSE_DEBUG
6520Sstevel@tonic-gate 				printf("ERR: T_EXP is followed by %s\n",
6530Sstevel@tonic-gate 					type_name[type]);
6540Sstevel@tonic-gate #endif
6550Sstevel@tonic-gate 				STACKFREE;
6560Sstevel@tonic-gate 				return (1);
6570Sstevel@tonic-gate 			}
6580Sstevel@tonic-gate 			exp = setop1(op, 0, stk, flag);
6590Sstevel@tonic-gate 			if (!exp)
6600Sstevel@tonic-gate 				return (-1);
6610Sstevel@tonic-gate 			ret = stack_push(stk, exp);
6620Sstevel@tonic-gate 			if (!ret)
6630Sstevel@tonic-gate 				return (1);
6640Sstevel@tonic-gate 			flag = op;
6650Sstevel@tonic-gate 			continue;			/* while-loop */
6660Sstevel@tonic-gate 		}
6670Sstevel@tonic-gate 		if ((type == T_NUM) || (type == T_VAR)) {
6680Sstevel@tonic-gate 			exp = setop1(op, type == T_NUM ? num : 0, stk, flag);
6690Sstevel@tonic-gate 			if (!exp)
6700Sstevel@tonic-gate 				return (-1);
6710Sstevel@tonic-gate exp_check:
6720Sstevel@tonic-gate 			ftype = GETTYPE(flag);
6730Sstevel@tonic-gate 			if ((ftype == T_INIT) || (ftype == T_LPAR)) {
6740Sstevel@tonic-gate 				/*
6750Sstevel@tonic-gate 				 * if this NUM/VAR is the first EXP,
6760Sstevel@tonic-gate 				 * just push this
6770Sstevel@tonic-gate 				 */
6780Sstevel@tonic-gate 				exp->flag = flag;
6790Sstevel@tonic-gate 				ret = stack_push(stk, exp);
6800Sstevel@tonic-gate 				if (!ret)
6810Sstevel@tonic-gate 					return (1);
6820Sstevel@tonic-gate 				flag = operator[T_EXP];
6830Sstevel@tonic-gate 				continue;		/* while-loop */
6840Sstevel@tonic-gate 			}
6850Sstevel@tonic-gate 			if (ftype == T_EXP) {
6860Sstevel@tonic-gate 				/*
6870Sstevel@tonic-gate 				 * parse failed
6880Sstevel@tonic-gate 				 * NUM/VAR cannot be seen just after
6890Sstevel@tonic-gate 				 * T_EXP
6900Sstevel@tonic-gate 				 */
6910Sstevel@tonic-gate 				freeexpr(exp);
6920Sstevel@tonic-gate 				STACKFREE;
6930Sstevel@tonic-gate 				return (1);
6940Sstevel@tonic-gate 			}
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 			nop = gettoken(&pstr, &num, PEEK_TOKEN);
6970Sstevel@tonic-gate 			if (nop != T_NULL) {
6980Sstevel@tonic-gate 				ntype = GETTYPE(nop);
6990Sstevel@tonic-gate 				nprio = GETPRIO(nop);
7000Sstevel@tonic-gate 			} else {
7010Sstevel@tonic-gate 				(void) gettoken(&pstr, &num, GET_TOKEN);
7020Sstevel@tonic-gate 				ntype = T_INIT;
7030Sstevel@tonic-gate 				nprio = 0;
7040Sstevel@tonic-gate 			}
7050Sstevel@tonic-gate #ifdef	PARSE_DEBUG
7060Sstevel@tonic-gate printf("========================== T_NUM/T_VAR for loop in\n");
7070Sstevel@tonic-gate #endif
7080Sstevel@tonic-gate 			for (; ; ) {
7090Sstevel@tonic-gate 				ftype = GETTYPE(flag);
7100Sstevel@tonic-gate 				fopnum = GETOPNUM(flag);
7110Sstevel@tonic-gate 				fprio = GETPRIO(flag);
7120Sstevel@tonic-gate #ifdef	PARSE_DEBUG
7130Sstevel@tonic-gate 				printf("========= flag: %s\n",
7140Sstevel@tonic-gate 					type_name[ftype]);
7150Sstevel@tonic-gate #endif
7160Sstevel@tonic-gate 				if ((ftype == T_INIT) || (ftype == T_LPAR)) {
7170Sstevel@tonic-gate 					exp->flag = flag;
7180Sstevel@tonic-gate 					ret = stack_push(stk, exp);
7190Sstevel@tonic-gate 					if (!ret)
7200Sstevel@tonic-gate 						return (1);
7210Sstevel@tonic-gate 					flag = operator[T_EXP];
7220Sstevel@tonic-gate 					break;		/* exit from for-loop */
7230Sstevel@tonic-gate 				}
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 				if (ftype == T_LNOT) {
7260Sstevel@tonic-gate 					/* LNOT is the strongest */
7270Sstevel@tonic-gate 					result = reduce(&nexp, UNARY, exp, stk);
7280Sstevel@tonic-gate 					if (result)
7290Sstevel@tonic-gate 						return (result);
7300Sstevel@tonic-gate 					exp = nexp;
7310Sstevel@tonic-gate 					flag = nexp->flag;
7320Sstevel@tonic-gate 					continue;	/* for-loop */
7330Sstevel@tonic-gate 				}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 				if (fopnum == BINARY) {
7360Sstevel@tonic-gate 					/*
7370Sstevel@tonic-gate 					 * binary operation
7380Sstevel@tonic-gate 					 * T_MUL, T_ADD,  T_CMP,
7390Sstevel@tonic-gate 					 * T_EQ,  T_LAND, T_LOR
7400Sstevel@tonic-gate 					 */
7410Sstevel@tonic-gate 					if ((ntype == T_RPAR) ||
7420Sstevel@tonic-gate 						(nprio <= fprio)) {
7430Sstevel@tonic-gate 						/* reduce */
7440Sstevel@tonic-gate 						result = reduce(&nexp, BINARY,
7450Sstevel@tonic-gate 							exp, stk);
7460Sstevel@tonic-gate 						if (result)
7470Sstevel@tonic-gate 							return (result);
7480Sstevel@tonic-gate 						exp = nexp;
7490Sstevel@tonic-gate 						flag = nexp->flag;
7500Sstevel@tonic-gate 						continue; /* for-loop */
7510Sstevel@tonic-gate 					}
7520Sstevel@tonic-gate 					/* shift */
7530Sstevel@tonic-gate 					exp->flag = flag;
7540Sstevel@tonic-gate 					ret = stack_push(stk, exp);
7550Sstevel@tonic-gate 					if (!ret)
7560Sstevel@tonic-gate 						return (1);
7570Sstevel@tonic-gate 					flag = operator[T_EXP];
7580Sstevel@tonic-gate 					break;		/* exit from for loop */
7590Sstevel@tonic-gate 				}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 				if (ftype == T_CONDQ) {
7620Sstevel@tonic-gate 					/*
7630Sstevel@tonic-gate 					 * CONDQ is the weakest
7640Sstevel@tonic-gate 					 * always shift
7650Sstevel@tonic-gate 					 */
7660Sstevel@tonic-gate 					exp->flag = flag;
7670Sstevel@tonic-gate 					ret = stack_push(stk, exp);
7680Sstevel@tonic-gate 					if (!ret)
7690Sstevel@tonic-gate 						return (1);
7700Sstevel@tonic-gate 					flag = operator[T_EXP];
7710Sstevel@tonic-gate 					break;		/* exit from for loop */
7720Sstevel@tonic-gate 				}
7730Sstevel@tonic-gate 				if (ftype == T_CONDC) {
7740Sstevel@tonic-gate 					if (nprio <= fprio) {
7750Sstevel@tonic-gate 						/* reduce */
7760Sstevel@tonic-gate 						result = reduce(&nexp, TRINARY,
7770Sstevel@tonic-gate 							exp, stk);
7780Sstevel@tonic-gate 						if (result)
7790Sstevel@tonic-gate 							return (result);
7800Sstevel@tonic-gate 						exp = nexp;
7810Sstevel@tonic-gate 						flag = nexp->flag;
7820Sstevel@tonic-gate 						continue; /* for-loop */
7830Sstevel@tonic-gate 					}
7840Sstevel@tonic-gate 					/* shift */
7850Sstevel@tonic-gate 					exp->flag = flag;
7860Sstevel@tonic-gate 					ret = stack_push(stk, exp);
7870Sstevel@tonic-gate 					if (!ret)
7880Sstevel@tonic-gate 						return (1);
7890Sstevel@tonic-gate 					flag = operator[T_EXP];
7900Sstevel@tonic-gate 					break;		/* exit from for-loop */
7910Sstevel@tonic-gate 				}
7920Sstevel@tonic-gate 				/* parse failed */
7930Sstevel@tonic-gate 				freeexpr(exp);
7940Sstevel@tonic-gate 				STACKFREE;
7950Sstevel@tonic-gate 				return (1);
7960Sstevel@tonic-gate 			}
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate #ifdef	PARSE_DEBUG
7990Sstevel@tonic-gate printf("======================= T_NUM/T_VAR for loop out\n");
8000Sstevel@tonic-gate #endif
8010Sstevel@tonic-gate 			continue;			/* while-loop */
8020Sstevel@tonic-gate 		}
8030Sstevel@tonic-gate 		/* parse failed */
8040Sstevel@tonic-gate 		STACKFREE;
8050Sstevel@tonic-gate 		return (1);
8060Sstevel@tonic-gate 	} 	/* while-loop */
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if (GETTYPE(flag) != T_EXP) {
8090Sstevel@tonic-gate 		/* parse failed */
8100Sstevel@tonic-gate #ifdef	PARSE_DEBUG
8110Sstevel@tonic-gate 		printf("XXXX ERROR: flag is not T_INIT\n");
8120Sstevel@tonic-gate 		printf("========= flag: %s\n", type_name[GETTYPE(flag)]);
8130Sstevel@tonic-gate #endif
8140Sstevel@tonic-gate 		STACKFREE;
8150Sstevel@tonic-gate 		return (1);
8160Sstevel@tonic-gate 	} else {
8170Sstevel@tonic-gate 		exp = stack_pop(stk, NULL, NULL);
8180Sstevel@tonic-gate 		if (!exp)
8190Sstevel@tonic-gate 			return (1);
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		if (GETTYPE(exp->flag) != T_INIT) {
8220Sstevel@tonic-gate 			/* parse failed */
8230Sstevel@tonic-gate #ifdef	PARSE_DEBUG
8240Sstevel@tonic-gate 			printf("ERR: flag for the result is not T_INIT\n");
8250Sstevel@tonic-gate 			printf("      %s observed\n",
8260Sstevel@tonic-gate 				type_name[GETTYPE(exp->flag)]);
8270Sstevel@tonic-gate #endif
8280Sstevel@tonic-gate 			freeexpr(exp);
8290Sstevel@tonic-gate 			STACKFREE;
8300Sstevel@tonic-gate 			return (1);
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 		if (stk->index > 0) {
8330Sstevel@tonic-gate 			/*
8340Sstevel@tonic-gate 			 * exp still remains in stack.
8350Sstevel@tonic-gate 			 * parse failed
8360Sstevel@tonic-gate 			 */
8370Sstevel@tonic-gate 			while (nexp = stack_pop(stk, NULL, NULL))
8380Sstevel@tonic-gate 				freeexpr(nexp);
8390Sstevel@tonic-gate 			freeexpr(exp);
8400Sstevel@tonic-gate 			return (1);
8410Sstevel@tonic-gate 		}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		/* parse succeeded */
8440Sstevel@tonic-gate 		*e = exp;
8450Sstevel@tonic-gate 		STACKFREE;
8460Sstevel@tonic-gate 		return (0);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate unsigned int
plural_eval(struct expr * exp,unsigned int n)8510Sstevel@tonic-gate plural_eval(struct expr *exp, unsigned int n)
8520Sstevel@tonic-gate {
8530Sstevel@tonic-gate 	unsigned int	e1, e2;
8540Sstevel@tonic-gate 	unsigned int	type, opnum;
8550Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
8560Sstevel@tonic-gate 	(void) printf("*************** plural_eval(%p, %d)\n",
8570Sstevel@tonic-gate 		exp, n);
8580Sstevel@tonic-gate 	printexpr(exp, 0);
8590Sstevel@tonic-gate #endif
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	type = GETTYPE(exp->op);
8620Sstevel@tonic-gate 	opnum = GETOPNUM(exp->op);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	switch (opnum) {
8650Sstevel@tonic-gate 	case NARY:
8660Sstevel@tonic-gate 		if (type == T_NUM) {
8670Sstevel@tonic-gate 			return (exp->num);
8680Sstevel@tonic-gate 		} else if (type == T_VAR) {
8690Sstevel@tonic-gate 			return (n);
8700Sstevel@tonic-gate 		}
8710Sstevel@tonic-gate 		break;
8720Sstevel@tonic-gate 	case UNARY:
8730Sstevel@tonic-gate 		/* T_LNOT */
8740Sstevel@tonic-gate 		e1 = plural_eval(exp->nodes[0], n);
8750Sstevel@tonic-gate 		return (!e1);
8760Sstevel@tonic-gate 	case BINARY:
8770Sstevel@tonic-gate 		e1 = plural_eval(exp->nodes[0], n);
8780Sstevel@tonic-gate 		/* optimization for T_LOR and T_LAND */
8790Sstevel@tonic-gate 		if (type == T_LOR) {
8800Sstevel@tonic-gate 			return (e1 || plural_eval(exp->nodes[1], n));
8810Sstevel@tonic-gate 		} else if (type == T_LAND) {
8820Sstevel@tonic-gate 			return (e1 && plural_eval(exp->nodes[1], n));
8830Sstevel@tonic-gate 		}
8840Sstevel@tonic-gate 		e2 = plural_eval(exp->nodes[1], n);
8850Sstevel@tonic-gate 		switch (type) {
8860Sstevel@tonic-gate 		case T_EQ:
8870Sstevel@tonic-gate 			return (e1 == e2);
8880Sstevel@tonic-gate 		case T_NEQ:
8890Sstevel@tonic-gate 			return (e1 != e2);
8900Sstevel@tonic-gate 		case T_GT:
8910Sstevel@tonic-gate 			return (e1 > e2);
8920Sstevel@tonic-gate 		case T_LT:
8930Sstevel@tonic-gate 			return (e1 < e2);
8940Sstevel@tonic-gate 		case T_GE:
8950Sstevel@tonic-gate 			return (e1 >= e2);
8960Sstevel@tonic-gate 		case T_LE:
8970Sstevel@tonic-gate 			return (e1 <= e2);
8980Sstevel@tonic-gate 		case T_ADD:
8990Sstevel@tonic-gate 			return (e1 + e2);
9000Sstevel@tonic-gate 		case T_SUB:
9010Sstevel@tonic-gate 			return (e1 - e2);
9020Sstevel@tonic-gate 		case T_MUL:
9030Sstevel@tonic-gate 			return (e1 * e2);
9040Sstevel@tonic-gate 		case T_DIV:
9050Sstevel@tonic-gate 			if (e2 != 0)
9060Sstevel@tonic-gate 				return (e1 / e2);
9070Sstevel@tonic-gate 			break;
9080Sstevel@tonic-gate 		case T_MOD:
9090Sstevel@tonic-gate 			if (e2 != 0)
9100Sstevel@tonic-gate 				return (e1 % e2);
9110Sstevel@tonic-gate 			break;
9120Sstevel@tonic-gate 		}
9130Sstevel@tonic-gate 		break;
9140Sstevel@tonic-gate 	case TRINARY:
9150Sstevel@tonic-gate 		/* T_CONDQ */
9160Sstevel@tonic-gate 		e1 = plural_eval(exp->nodes[0], n);
9170Sstevel@tonic-gate 		if (e1) {
9180Sstevel@tonic-gate 			return (plural_eval(exp->nodes[1], n));
9190Sstevel@tonic-gate 		} else {
9200Sstevel@tonic-gate 			return (plural_eval(exp->nodes[2], n));
9210Sstevel@tonic-gate 		}
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 	/* should not be here */
9240Sstevel@tonic-gate 	return (0);
9250Sstevel@tonic-gate }
926