dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libc / port / i18n / plural_parser.c
blob408d1b558dedae05f863cb736ea58a46e42fcc06
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "lint.h"
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include "libc.h"
34 #include "gettext.h"
36 #include "plural_parser.h"
39 * 31 28 24 20 16 12 8 4 0
40 * +-----+-----+-----+-----+-----+-----+-----+-----+
41 * |opnum| priority | operator |
42 * +-----+-----+-----+-----+-----+-----+-----+-----+
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 */
71 #define STACKFREE \
72 { \
73 while (stk->index > 0) \
74 freeexpr(stk->ptr[--stk->index]); \
75 free(stk->ptr); \
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"
86 #endif
88 static void freeexpr(struct expr *);
90 static struct expr *
91 stack_push(struct stack *stk, struct expr *exp)
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);
107 return (exp);
110 static struct expr *
111 stack_pop(struct stack *stk,
112 struct expr *exp_a, struct expr *exp_b)
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);
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]);
134 static void
135 freeexpr(struct expr *e)
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;
158 free(e);
161 static struct expr *
162 setop1(unsigned int op, unsigned int num,
163 struct stack *stk, unsigned int flag)
165 struct expr *newitem;
166 unsigned int type;
168 type = GETTYPE(op);
170 #ifdef PARSE_DEBUG
171 printf("---setop1---\n");
172 printf(" op type: %s\n", type_name[type]);
173 printf("-----------\n");
174 #endif
176 newitem = (struct expr *)calloc(1, sizeof (struct expr));
177 if (!newitem) {
178 STACKFREE;
179 return (NULL);
181 newitem->op = op;
182 if (type == T_NUM)
183 newitem->num = num;
184 newitem->flag = flag;
185 return (newitem);
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)
192 struct expr *newitem;
193 #ifdef PARSE_DEBUG
194 unsigned int type;
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;
213 printf("-----------\n");
214 #endif
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);
227 newitem->op = op;
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;
242 return (newitem);
245 static int
246 reduce(struct expr **nexp, unsigned int n, struct expr *exp, struct stack *stk)
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
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);
310 oop = exp_op->op;
311 freeexpr(exp_op);
312 exp1 = stack_pop(stk, exp2, exp3);
313 if (!exp1)
314 return (1);
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);
323 /* NOTREACHED */
324 return (0); /* keep gcc happy */
327 static unsigned int
328 gettoken(const char **pstr, unsigned int *num, int which)
330 unsigned char *sp = *(unsigned char **)pstr;
331 unsigned int n;
332 unsigned int ret;
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);
342 if (isdigit(*sp)) {
343 n = *sp - '0';
344 sp++;
345 while (isdigit(*sp)) {
346 n *= 10;
347 n += *sp - '0';
348 sp++;
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;
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;
392 } else if (*sp == '>') {
393 sp++;
394 if (*sp == '=') {
395 sp++;
396 ret = T_GE;
397 } else {
398 ret = T_GT;
400 } else if (*sp == '=') {
401 sp++;
402 if (*sp == '=') {
403 sp++;
404 ret = T_EQ;
405 } else {
406 ret = T_ERR;
408 } else if (*sp == '&') {
409 sp++;
410 if (*sp == '&') {
411 sp++;
412 ret = T_LAND;
413 } else {
414 ret = T_ERR;
416 } else if (*sp == '|') {
417 sp++;
418 if (*sp == '|') {
419 sp++;
420 ret = T_LOR;
421 } else {
422 ret = T_ERR;
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;
435 if (which == GET_TOKEN)
436 *pstr = (const char *)sp;
437 return (operator[ret]);
441 * plural_expr
443 * INPUT
444 * str: string to parse
446 * OUTPUT
447 * e: parsed expression
449 * RETURN
450 * -1: Error happend (malloc failed)
451 * 1: Parse failed (invalid expression)
452 * 0: Parse succeeded
455 plural_expr(struct expr **e, const char *plural_string)
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;
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);
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);
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);
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);
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 */
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);
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 */
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);
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 */
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);
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 */
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);
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);
595 exp = stack_pop(stk, NULL, NULL);
596 if (!exp)
597 return (1);
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);
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);
615 tmp_flag = exp_op->flag;
616 freeexpr(exp_op);
618 exp->flag = tmp_flag;
619 flag = tmp_flag;
620 break; /* break from for-loop */
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 */
633 /* parse failed */
634 freeexpr(exp);
635 STACKFREE;
636 return (1);
637 } /* for-loop */
639 #ifdef PARSE_DEBUG
640 printf("========================= RPAR for loop out\n");
641 #endif
643 * Needs to check if exp can be reduced or not
645 goto exp_check;
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);
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 */
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)) {
675 * if this NUM/VAR is the first EXP,
676 * just push this
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 */
685 if (ftype == T_EXP) {
687 * parse failed
688 * NUM/VAR cannot be seen just after
689 * T_EXP
691 freeexpr(exp);
692 STACKFREE;
693 return (1);
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;
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 */
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 */
735 if (fopnum == BINARY) {
737 * binary operation
738 * T_MUL, T_ADD, T_CMP,
739 * T_EQ, T_LAND, T_LOR
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 */
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 */
761 if (ftype == T_CONDQ) {
763 * CONDQ is the weakest
764 * always shift
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 */
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 */
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 */
792 /* parse failed */
793 freeexpr(exp);
794 STACKFREE;
795 return (1);
798 #ifdef PARSE_DEBUG
799 printf("======================= T_NUM/T_VAR for loop out\n");
800 #endif
801 continue; /* while-loop */
803 /* parse failed */
804 STACKFREE;
805 return (1);
806 } /* while-loop */
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);
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);
832 if (stk->index > 0) {
834 * exp still remains in stack.
835 * parse failed
837 while (nexp = stack_pop(stk, NULL, NULL))
838 freeexpr(nexp);
839 freeexpr(exp);
840 return (1);
843 /* parse succeeded */
844 *e = exp;
845 STACKFREE;
846 return (0);
850 unsigned int
851 plural_eval(struct expr *exp, unsigned int n)
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
861 type = GETTYPE(exp->op);
862 opnum = GETOPNUM(exp->op);
864 switch (opnum) {
865 case NARY:
866 if (type == T_NUM) {
867 return (exp->num);
868 } else if (type == T_VAR) {
869 return (n);
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));
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;
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));
923 /* should not be here */
924 return (0);