2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include "lint.h"
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include "libc.h"
2N/A#include "gettext.h"
2N/A
2N/A#include "plural_parser.h"
2N/A
2N/A/*
2N/A * 31 28 24 20 16 12 8 4 0
2N/A * +-----+-----+-----+-----+-----+-----+-----+-----+
2N/A * |opnum| priority | operator |
2N/A * +-----+-----+-----+-----+-----+-----+-----+-----+
2N/A */
2N/Astatic const unsigned int operator[] = {
2N/A 0x00000000, /* NULL */
2N/A 0x00000001, /* INIT */
2N/A 0x00100002, /* EXP */
2N/A 0x00200003, /* NUM */
2N/A 0x00300004, /* VAR */
2N/A 0x30400005, /* CONDC */
2N/A 0x30500006, /* CONDQ */
2N/A 0x20600007, /* OR */
2N/A 0x20700008, /* AND */
2N/A 0x20800009, /* EQ */
2N/A 0x2080000a, /* NEQ */
2N/A 0x2090000b, /* GT */
2N/A 0x2090000c, /* LT */
2N/A 0x2090000d, /* GE */
2N/A 0x2090000e, /* LE */
2N/A 0x20a0000f, /* ADD */
2N/A 0x20a00010, /* SUB */
2N/A 0x20b00011, /* MUL */
2N/A 0x20b00012, /* DIV */
2N/A 0x20b00013, /* MOD */
2N/A 0x10c00014, /* NOT */
2N/A 0x00d00015, /* LPAR */
2N/A 0x00e00016, /* RPAR */
2N/A 0x00000017 /* ERR */
2N/A};
2N/A
2N/A#define STACKFREE \
2N/A { \
2N/A while (stk->index > 0) \
2N/A freeexpr(stk->ptr[--stk->index]); \
2N/A free(stk->ptr); \
2N/A }
2N/A
2N/A#ifdef PARSE_DEBUG
2N/Astatic const char *type_name[] = {
2N/A "T_NULL",
2N/A "T_INIT", "T_EXP", "T_NUM", "T_VAR", "T_CONDC", "T_CONDQ",
2N/A "T_LOR", "T_LAND", "T_EQ", "T_NEQ", "T_GT", "T_LT", "T_GE", "T_LE",
2N/A "T_ADD", "T_SUB", "T_MUL", "T_DIV", "T_MOD", "T_LNOT", "T_LPAR",
2N/A "T_RPAR", "T_ERR"
2N/A};
2N/A#endif
2N/A
2N/Astatic void freeexpr(struct expr *);
2N/A
2N/Astatic struct expr *
2N/Astack_push(struct stack *stk, struct expr *exp)
2N/A{
2N/A#ifdef PARSE_DEBUG
2N/A printf("--- stack_push ---\n");
2N/A printf(" type: %s\n", type_name[GETTYPE(exp->op)]);
2N/A printf(" flag: %s\n", type_name[GETTYPE(exp->flag)]);
2N/A printf("------------------\n");
2N/A#endif
2N/A stk->ptr[stk->index++] = exp;
2N/A if (stk->index == MAX_STACK_SIZE) {
2N/A /* overflow */
2N/A freeexpr(exp);
2N/A STACKFREE;
2N/A return (NULL);
2N/A }
2N/A
2N/A return (exp);
2N/A}
2N/A
2N/Astatic struct expr *
2N/Astack_pop(struct stack *stk,
2N/A struct expr *exp_a, struct expr *exp_b)
2N/A{
2N/A if (stk->index == 0) {
2N/A /* no item */
2N/A if (exp_a)
2N/A freeexpr(exp_a);
2N/A if (exp_b)
2N/A freeexpr(exp_b);
2N/A STACKFREE;
2N/A return (NULL);
2N/A }
2N/A#ifdef PARSE_DEBUG
2N/A printf("--- stack_pop ---\n");
2N/A printf(" type: %s\n",
2N/A type_name[GETTYPE((stk->ptr[stk->index - 1])->op)]);
2N/A printf(" flag: %s\n",
2N/A type_name[GETTYPE((stk->ptr[stk->index - 1])->flag)]);
2N/A printf("-----------------\n");
2N/A#endif
2N/A return (stk->ptr[--stk->index]);
2N/A}
2N/A
2N/Astatic void
2N/Afreeexpr(struct expr *e)
2N/A{
2N/A#ifdef PARSE_DEBUG
2N/A printf("--- freeexpr ---\n");
2N/A printf(" type: %s\n", type_name[GETTYPE(e->op)]);
2N/A printf("----------------\n");
2N/A#endif
2N/A switch (GETOPNUM(e->op)) {
2N/A case TRINARY:
2N/A if (e->nodes[2])
2N/A freeexpr(e->nodes[2]);
2N/A /* FALLTHROUGH */
2N/A case BINARY:
2N/A if (e->nodes[1])
2N/A freeexpr(e->nodes[1]);
2N/A /* FALLTHROUGH */
2N/A case UNARY:
2N/A if (e->nodes[0])
2N/A freeexpr(e->nodes[0]);
2N/A /* FALLTHROUGH */
2N/A default:
2N/A break;
2N/A }
2N/A free(e);
2N/A}
2N/A
2N/Astatic struct expr *
2N/Asetop1(unsigned int op, unsigned int num,
2N/A struct stack *stk, unsigned int flag)
2N/A{
2N/A struct expr *newitem;
2N/A unsigned int type;
2N/A
2N/A type = GETTYPE(op);
2N/A
2N/A#ifdef PARSE_DEBUG
2N/A printf("---setop1---\n");
2N/A printf(" op type: %s\n", type_name[type]);
2N/A printf("-----------\n");
2N/A#endif
2N/A
2N/A newitem = (struct expr *)calloc(1, sizeof (struct expr));
2N/A if (!newitem) {
2N/A STACKFREE;
2N/A return (NULL);
2N/A }
2N/A newitem->op = op;
2N/A if (type == T_NUM)
2N/A newitem->num = num;
2N/A newitem->flag = flag;
2N/A return (newitem);
2N/A}
2N/A
2N/Astatic struct expr *
2N/Asetop_reduce(unsigned int n, unsigned int op, struct stack *stk,
2N/A struct expr *exp1, struct expr *exp2, struct expr *exp3)
2N/A{
2N/A struct expr *newitem;
2N/A#ifdef PARSE_DEBUG
2N/A unsigned int type;
2N/A
2N/A type = GETTYPE(op);
2N/A printf("---setop_reduce---\n");
2N/A printf(" n: %d\n", n);
2N/A printf(" op type: %s\n", type_name[type]);
2N/A switch (n) {
2N/A case TRINARY:
2N/A printf(" exp3 type: %s\n",
2N/A type_name[GETTYPE(exp3->op)]);
2N/A case BINARY:
2N/A printf(" exp2 type: %s\n",
2N/A type_name[GETTYPE(exp2->op)]);
2N/A case UNARY:
2N/A printf(" exp1 type: %s\n",
2N/A type_name[GETTYPE(exp1->op)]);
2N/A case NARY:
2N/A break;
2N/A }
2N/A printf("-----------\n");
2N/A#endif
2N/A
2N/A newitem = (struct expr *)calloc(1, sizeof (struct expr));
2N/A if (!newitem) {
2N/A if (exp1)
2N/A freeexpr(exp1);
2N/A if (exp2)
2N/A freeexpr(exp2);
2N/A if (exp3)
2N/A freeexpr(exp3);
2N/A STACKFREE;
2N/A return (NULL);
2N/A }
2N/A newitem->op = op;
2N/A
2N/A switch (n) {
2N/A case TRINARY:
2N/A newitem->nodes[2] = exp3;
2N/A /* FALLTHROUGH */
2N/A case BINARY:
2N/A newitem->nodes[1] = exp2;
2N/A /* FALLTHROUGH */
2N/A case UNARY:
2N/A newitem->nodes[0] = exp1;
2N/A /* FALLTHROUGH */
2N/A case NARY:
2N/A break;
2N/A }
2N/A return (newitem);
2N/A}
2N/A
2N/Astatic int
2N/Areduce(struct expr **nexp, unsigned int n, struct expr *exp, struct stack *stk)
2N/A{
2N/A struct expr *exp_op, *exp1, *exp2, *exp3;
2N/A unsigned int tmp_flag;
2N/A unsigned int oop;
2N/A#ifdef PARSE_DEBUG
2N/A printf("---reduce---\n");
2N/A printf(" n: %d\n", n);
2N/A printf("-----------\n");
2N/A#endif
2N/A
2N/A switch (n) {
2N/A case UNARY:
2N/A /* unary operator */
2N/A exp1 = exp;
2N/A exp_op = stack_pop(stk, exp1, NULL);
2N/A if (!exp_op)
2N/A return (1);
2N/A tmp_flag = exp_op->flag;
2N/A oop = exp_op->op;
2N/A freeexpr(exp_op);
2N/A *nexp = setop_reduce(UNARY, oop, stk, exp1, NULL, NULL);
2N/A if (!*nexp)
2N/A return (-1);
2N/A (*nexp)->flag = tmp_flag;
2N/A return (0);
2N/A case BINARY:
2N/A /* binary operator */
2N/A exp2 = exp;
2N/A exp_op = stack_pop(stk, exp2, NULL);
2N/A if (!exp_op)
2N/A return (1);
2N/A exp1 = stack_pop(stk, exp_op, exp2);
2N/A if (!exp1)
2N/A return (1);
2N/A tmp_flag = exp1->flag;
2N/A oop = exp_op->op;
2N/A freeexpr(exp_op);
2N/A *nexp = setop_reduce(BINARY, oop, stk, exp1, exp2, NULL);
2N/A if (!*nexp)
2N/A return (-1);
2N/A (*nexp)->flag = tmp_flag;
2N/A return (0);
2N/A case TRINARY:
2N/A /* trinary operator: conditional */
2N/A exp3 = exp;
2N/A exp_op = stack_pop(stk, exp3, NULL);
2N/A if (!exp_op)
2N/A return (1);
2N/A freeexpr(exp_op);
2N/A exp2 = stack_pop(stk, exp3, NULL);
2N/A if (!exp2)
2N/A return (1);
2N/A exp_op = stack_pop(stk, exp2, exp3);
2N/A if (!exp_op)
2N/A return (1);
2N/A if (GETTYPE(exp_op->op) != T_CONDQ) {
2N/A /* parse failed */
2N/A freeexpr(exp_op);
2N/A freeexpr(exp2);
2N/A freeexpr(exp3);
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A oop = exp_op->op;
2N/A freeexpr(exp_op);
2N/A exp1 = stack_pop(stk, exp2, exp3);
2N/A if (!exp1)
2N/A return (1);
2N/A
2N/A tmp_flag = exp1->flag;
2N/A *nexp = setop_reduce(TRINARY, oop, stk, exp1, exp2, exp3);
2N/A if (!*nexp)
2N/A return (-1);
2N/A (*nexp)->flag = tmp_flag;
2N/A return (0);
2N/A }
2N/A /* NOTREACHED */
2N/A return (0); /* keep gcc happy */
2N/A}
2N/A
2N/Astatic unsigned int
2N/Agettoken(const char **pstr, unsigned int *num, int which)
2N/A{
2N/A unsigned char *sp = *(unsigned char **)pstr;
2N/A unsigned int n;
2N/A unsigned int ret;
2N/A
2N/A while (*sp && ((*sp == ' ') || (*sp == '\t')))
2N/A sp++;
2N/A if (!*sp) {
2N/A if (which == GET_TOKEN)
2N/A *pstr = (const char *)sp;
2N/A return (T_NULL);
2N/A }
2N/A
2N/A if (isdigit(*sp)) {
2N/A n = *sp - '0';
2N/A sp++;
2N/A while (isdigit(*sp)) {
2N/A n *= 10;
2N/A n += *sp - '0';
2N/A sp++;
2N/A }
2N/A *num = n;
2N/A ret = T_NUM;
2N/A } else if (*sp == 'n') {
2N/A sp++;
2N/A ret = T_VAR;
2N/A } else if (*sp == '(') {
2N/A sp++;
2N/A ret = T_LPAR;
2N/A } else if (*sp == ')') {
2N/A sp++;
2N/A ret = T_RPAR;
2N/A } else if (*sp == '!') {
2N/A sp++;
2N/A if (*sp == '=') {
2N/A sp++;
2N/A ret = T_NEQ;
2N/A } else {
2N/A ret = T_LNOT;
2N/A }
2N/A } else if (*sp == '*') {
2N/A sp++;
2N/A ret = T_MUL;
2N/A } else if (*sp == '/') {
2N/A sp++;
2N/A ret = T_DIV;
2N/A } else if (*sp == '%') {
2N/A sp++;
2N/A ret = T_MOD;
2N/A } else if (*sp == '+') {
2N/A sp++;
2N/A ret = T_ADD;
2N/A } else if (*sp == '-') {
2N/A sp++;
2N/A ret = T_SUB;
2N/A } else if (*sp == '<') {
2N/A sp++;
2N/A if (*sp == '=') {
2N/A sp++;
2N/A ret = T_LE;
2N/A } else {
2N/A ret = T_LT;
2N/A }
2N/A } else if (*sp == '>') {
2N/A sp++;
2N/A if (*sp == '=') {
2N/A sp++;
2N/A ret = T_GE;
2N/A } else {
2N/A ret = T_GT;
2N/A }
2N/A } else if (*sp == '=') {
2N/A sp++;
2N/A if (*sp == '=') {
2N/A sp++;
2N/A ret = T_EQ;
2N/A } else {
2N/A ret = T_ERR;
2N/A }
2N/A } else if (*sp == '&') {
2N/A sp++;
2N/A if (*sp == '&') {
2N/A sp++;
2N/A ret = T_LAND;
2N/A } else {
2N/A ret = T_ERR;
2N/A }
2N/A } else if (*sp == '|') {
2N/A sp++;
2N/A if (*sp == '|') {
2N/A sp++;
2N/A ret = T_LOR;
2N/A } else {
2N/A ret = T_ERR;
2N/A }
2N/A } else if (*sp == '?') {
2N/A sp++;
2N/A ret = T_CONDQ;
2N/A } else if (*sp == ':') {
2N/A sp++;
2N/A ret = T_CONDC;
2N/A } else if ((*sp == '\n') || (*sp == ';')) {
2N/A ret = T_NULL;
2N/A } else {
2N/A ret = T_ERR;
2N/A }
2N/A if (which == GET_TOKEN)
2N/A *pstr = (const char *)sp;
2N/A return (operator[ret]);
2N/A}
2N/A
2N/A/*
2N/A * plural_expr
2N/A *
2N/A * INPUT
2N/A * str: string to parse
2N/A *
2N/A * OUTPUT
2N/A * e: parsed expression
2N/A *
2N/A * RETURN
2N/A * -1: Error happend (malloc failed)
2N/A * 1: Parse failed (invalid expression)
2N/A * 0: Parse succeeded
2N/A */
2N/Aint
2N/Aplural_expr(struct expr **e, const char *plural_string)
2N/A{
2N/A const char *pstr = plural_string;
2N/A struct stack *stk, stkbuf;
2N/A struct expr *exp, *nexp, *exp_op, *ret;
2N/A int par, result;
2N/A unsigned int flag, ftype, fprio, fopnum, tmp_flag;
2N/A unsigned int ntype, nprio, ptype, popnum;
2N/A unsigned int op, nop, num, type, opnum;
2N/A
2N/A stk = &stkbuf;
2N/A stk->index = 0;
2N/A stk->ptr = (struct expr **)malloc(
2N/A sizeof (struct expr *) * MAX_STACK_SIZE);
2N/A if (!stk->ptr) {
2N/A /* malloc failed */
2N/A return (-1);
2N/A }
2N/A
2N/A flag = operator[T_INIT];
2N/A par = 0;
2N/A while ((op = gettoken(&pstr, &num, GET_TOKEN)) != T_NULL) {
2N/A type = GETTYPE(op);
2N/A opnum = GETOPNUM(op);
2N/A ftype = GETTYPE(flag);
2N/A
2N/A#ifdef PARSE_DEBUG
2N/A printf("*** %s ***\n", type_name[type]);
2N/A printf(" flag: %s\n", type_name[ftype]);
2N/A printf(" par: %d\n", par);
2N/A printf("***********\n");
2N/A#endif
2N/A if (type == T_ERR) {
2N/A /* parse failed */
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A if (opnum == BINARY) {
2N/A /* binary operation */
2N/A if (ftype != T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is not followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = setop1(op, 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = op;
2N/A continue; /* while-loop */
2N/A }
2N/A
2N/A if (type == T_CONDQ) {
2N/A /* conditional operation: '?' */
2N/A if (ftype != T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is not followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = setop1(op, 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = op;
2N/A continue; /* while-loop */
2N/A }
2N/A if (type == T_CONDC) {
2N/A /* conditional operation: ':' */
2N/A if (ftype != T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is not followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = setop1(op, 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = op;
2N/A continue; /* while-loop */
2N/A }
2N/A
2N/A if (type == T_LPAR) {
2N/A /* left parenthesis */
2N/A if (ftype == T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = setop1(op, 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A par++;
2N/A flag = op;
2N/A continue; /* while-loop */
2N/A }
2N/A if (type == T_RPAR) {
2N/A /* right parenthesis */
2N/A if (ftype != T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is not followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A par--;
2N/A if (par < 0) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: too much T_RPAR\n");
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = stack_pop(stk, NULL, NULL);
2N/A if (!exp)
2N/A return (1);
2N/A
2N/A#ifdef PARSE_DEBUG
2N/A printf("======================== RPAR for loop in\n");
2N/A#endif
2N/A for (; ; ) {
2N/A ptype = GETTYPE(exp->flag);
2N/A popnum = GETOPNUM(exp->flag);
2N/A
2N/A#ifdef PARSE_DEBUG
2N/A printf("=========== exp->flag: %s\n",
2N/A type_name[ptype]);
2N/A#endif
2N/A if (ptype == T_LPAR) {
2N/A exp_op = stack_pop(stk, exp, NULL);
2N/A if (!exp_op)
2N/A return (1);
2N/A
2N/A tmp_flag = exp_op->flag;
2N/A freeexpr(exp_op);
2N/A
2N/A exp->flag = tmp_flag;
2N/A flag = tmp_flag;
2N/A break; /* break from for-loop */
2N/A }
2N/A
2N/A if ((popnum == BINARY) ||
2N/A (ptype == T_LNOT) ||
2N/A (ptype == T_CONDC)) {
2N/A result = reduce(&nexp, popnum,
2N/A exp, stk);
2N/A if (result)
2N/A return (result);
2N/A exp = nexp;
2N/A continue; /* for-loop */
2N/A }
2N/A /* parse failed */
2N/A freeexpr(exp);
2N/A STACKFREE;
2N/A return (1);
2N/A } /* for-loop */
2N/A
2N/A#ifdef PARSE_DEBUG
2N/Aprintf("========================= RPAR for loop out\n");
2N/A#endif
2N/A /*
2N/A * Needs to check if exp can be reduced or not
2N/A */
2N/A goto exp_check;
2N/A }
2N/A
2N/A if (type == T_LNOT) {
2N/A if (ftype == T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: T_EXP is followed by %s\n",
2N/A type_name[type]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A exp = setop1(op, 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = op;
2N/A continue; /* while-loop */
2N/A }
2N/A if ((type == T_NUM) || (type == T_VAR)) {
2N/A exp = setop1(op, type == T_NUM ? num : 0, stk, flag);
2N/A if (!exp)
2N/A return (-1);
2N/Aexp_check:
2N/A ftype = GETTYPE(flag);
2N/A if ((ftype == T_INIT) || (ftype == T_LPAR)) {
2N/A /*
2N/A * if this NUM/VAR is the first EXP,
2N/A * just push this
2N/A */
2N/A exp->flag = flag;
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = operator[T_EXP];
2N/A continue; /* while-loop */
2N/A }
2N/A if (ftype == T_EXP) {
2N/A /*
2N/A * parse failed
2N/A * NUM/VAR cannot be seen just after
2N/A * T_EXP
2N/A */
2N/A freeexpr(exp);
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A
2N/A nop = gettoken(&pstr, &num, PEEK_TOKEN);
2N/A if (nop != T_NULL) {
2N/A ntype = GETTYPE(nop);
2N/A nprio = GETPRIO(nop);
2N/A } else {
2N/A (void) gettoken(&pstr, &num, GET_TOKEN);
2N/A ntype = T_INIT;
2N/A nprio = 0;
2N/A }
2N/A#ifdef PARSE_DEBUG
2N/Aprintf("========================== T_NUM/T_VAR for loop in\n");
2N/A#endif
2N/A for (; ; ) {
2N/A ftype = GETTYPE(flag);
2N/A fopnum = GETOPNUM(flag);
2N/A fprio = GETPRIO(flag);
2N/A#ifdef PARSE_DEBUG
2N/A printf("========= flag: %s\n",
2N/A type_name[ftype]);
2N/A#endif
2N/A if ((ftype == T_INIT) || (ftype == T_LPAR)) {
2N/A exp->flag = flag;
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = operator[T_EXP];
2N/A break; /* exit from for-loop */
2N/A }
2N/A
2N/A if (ftype == T_LNOT) {
2N/A /* LNOT is the strongest */
2N/A result = reduce(&nexp, UNARY, exp, stk);
2N/A if (result)
2N/A return (result);
2N/A exp = nexp;
2N/A flag = nexp->flag;
2N/A continue; /* for-loop */
2N/A }
2N/A
2N/A if (fopnum == BINARY) {
2N/A /*
2N/A * binary operation
2N/A * T_MUL, T_ADD, T_CMP,
2N/A * T_EQ, T_LAND, T_LOR
2N/A */
2N/A if ((ntype == T_RPAR) ||
2N/A (nprio <= fprio)) {
2N/A /* reduce */
2N/A result = reduce(&nexp, BINARY,
2N/A exp, stk);
2N/A if (result)
2N/A return (result);
2N/A exp = nexp;
2N/A flag = nexp->flag;
2N/A continue; /* for-loop */
2N/A }
2N/A /* shift */
2N/A exp->flag = flag;
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = operator[T_EXP];
2N/A break; /* exit from for loop */
2N/A }
2N/A
2N/A if (ftype == T_CONDQ) {
2N/A /*
2N/A * CONDQ is the weakest
2N/A * always shift
2N/A */
2N/A exp->flag = flag;
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = operator[T_EXP];
2N/A break; /* exit from for loop */
2N/A }
2N/A if (ftype == T_CONDC) {
2N/A if (nprio <= fprio) {
2N/A /* reduce */
2N/A result = reduce(&nexp, TRINARY,
2N/A exp, stk);
2N/A if (result)
2N/A return (result);
2N/A exp = nexp;
2N/A flag = nexp->flag;
2N/A continue; /* for-loop */
2N/A }
2N/A /* shift */
2N/A exp->flag = flag;
2N/A ret = stack_push(stk, exp);
2N/A if (!ret)
2N/A return (1);
2N/A flag = operator[T_EXP];
2N/A break; /* exit from for-loop */
2N/A }
2N/A /* parse failed */
2N/A freeexpr(exp);
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A
2N/A#ifdef PARSE_DEBUG
2N/Aprintf("======================= T_NUM/T_VAR for loop out\n");
2N/A#endif
2N/A continue; /* while-loop */
2N/A }
2N/A /* parse failed */
2N/A STACKFREE;
2N/A return (1);
2N/A } /* while-loop */
2N/A
2N/A if (GETTYPE(flag) != T_EXP) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("XXXX ERROR: flag is not T_INIT\n");
2N/A printf("========= flag: %s\n", type_name[GETTYPE(flag)]);
2N/A#endif
2N/A STACKFREE;
2N/A return (1);
2N/A } else {
2N/A exp = stack_pop(stk, NULL, NULL);
2N/A if (!exp)
2N/A return (1);
2N/A
2N/A if (GETTYPE(exp->flag) != T_INIT) {
2N/A /* parse failed */
2N/A#ifdef PARSE_DEBUG
2N/A printf("ERR: flag for the result is not T_INIT\n");
2N/A printf(" %s observed\n",
2N/A type_name[GETTYPE(exp->flag)]);
2N/A#endif
2N/A freeexpr(exp);
2N/A STACKFREE;
2N/A return (1);
2N/A }
2N/A if (stk->index > 0) {
2N/A /*
2N/A * exp still remains in stack.
2N/A * parse failed
2N/A */
2N/A while (nexp = stack_pop(stk, NULL, NULL))
2N/A freeexpr(nexp);
2N/A freeexpr(exp);
2N/A return (1);
2N/A }
2N/A
2N/A /* parse succeeded */
2N/A *e = exp;
2N/A STACKFREE;
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/Aunsigned int
2N/Aplural_eval(struct expr *exp, unsigned int n)
2N/A{
2N/A unsigned int e1, e2;
2N/A unsigned int type, opnum;
2N/A#ifdef GETTEXT_DEBUG
2N/A (void) printf("*************** plural_eval(%p, %d)\n",
2N/A exp, n);
2N/A printexpr(exp, 0);
2N/A#endif
2N/A
2N/A type = GETTYPE(exp->op);
2N/A opnum = GETOPNUM(exp->op);
2N/A
2N/A switch (opnum) {
2N/A case NARY:
2N/A if (type == T_NUM) {
2N/A return (exp->num);
2N/A } else if (type == T_VAR) {
2N/A return (n);
2N/A }
2N/A break;
2N/A case UNARY:
2N/A /* T_LNOT */
2N/A e1 = plural_eval(exp->nodes[0], n);
2N/A return (!e1);
2N/A case BINARY:
2N/A e1 = plural_eval(exp->nodes[0], n);
2N/A /* optimization for T_LOR and T_LAND */
2N/A if (type == T_LOR) {
2N/A return (e1 || plural_eval(exp->nodes[1], n));
2N/A } else if (type == T_LAND) {
2N/A return (e1 && plural_eval(exp->nodes[1], n));
2N/A }
2N/A e2 = plural_eval(exp->nodes[1], n);
2N/A switch (type) {
2N/A case T_EQ:
2N/A return (e1 == e2);
2N/A case T_NEQ:
2N/A return (e1 != e2);
2N/A case T_GT:
2N/A return (e1 > e2);
2N/A case T_LT:
2N/A return (e1 < e2);
2N/A case T_GE:
2N/A return (e1 >= e2);
2N/A case T_LE:
2N/A return (e1 <= e2);
2N/A case T_ADD:
2N/A return (e1 + e2);
2N/A case T_SUB:
2N/A return (e1 - e2);
2N/A case T_MUL:
2N/A return (e1 * e2);
2N/A case T_DIV:
2N/A if (e2 != 0)
2N/A return (e1 / e2);
2N/A break;
2N/A case T_MOD:
2N/A if (e2 != 0)
2N/A return (e1 % e2);
2N/A break;
2N/A }
2N/A break;
2N/A case TRINARY:
2N/A /* T_CONDQ */
2N/A e1 = plural_eval(exp->nodes[0], n);
2N/A if (e1) {
2N/A return (plural_eval(exp->nodes[1], n));
2N/A } else {
2N/A return (plural_eval(exp->nodes[2], n));
2N/A }
2N/A }
2N/A /* should not be here */
2N/A return (0);
2N/A}