From: Bruno Haible Date: Mon, 19 Mar 2001 17:43:35 +0000 (+0000) Subject: Rework the last plural.y changes, for clarity, and optimize for space. X-Git-Tag: v0.10.36~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36d52088b78bc3a741b59f57d8b04d71178da666;p=thirdparty%2Fgettext.git Rework the last plural.y changes, for clarity, and optimize for space. --- diff --git a/intl/ChangeLog b/intl/ChangeLog index c060623dd..647518a32 100644 --- a/intl/ChangeLog +++ b/intl/ChangeLog @@ -1,16 +1,30 @@ -2001-03-16 Bruno Haible +2001-03-17 Bruno Haible * gettextP.h (struct expression): Add operators lnot, less_than, - greater_than, less_or_equal, greater_or_equal. Add args1 to union. - * plural.y ('?' ':'): Make right-associative. - ('<', '>', LE, GE, '!'): New operators. - (EQ): Renamed from '='. - (NE): Renamed from '!'. - (exp): Add rules with these operators. + greater_than, less_or_equal, greater_or_equal. Replace args2/args3 + union by a 'nargs' counter and an 'args[]' array. + * plural.y: Don't include stdarg.h. + (new_exp): New function. + (new_exp_0, new_exp_2, new_exp_3): Rewritten to call new_exp. (new_exp_1): New function. - (FREE_EXPRESSION): Recognize these operators. - (yylex): Don't skip "\\n". Recognize '<', '>', LE, GE, '!' operators. - * dcigettext.c (plural_eval): Recognize these operators. + ('?' ':'): Make right-associative. + (EQUOP2): New token, replaces '=' and '!'. + (CMPOP2): New token. + (ADDOP2): New token, replaces '+' and '-'. + (MULOP2): New token, replaces '*', '/' and '%'. + ('!'): New token. + (exp): Add rules for CMPOP2 and '!'. Don't call YYABORT. + (start): Call YYABORT here. + (FREE_EXPRESSION): Update. + (yylex): Don't skip "\\n". Recognize comparison and '!' operators. + Update for new token symbols. + * loadmsgcat.c (plvar, plone, germanic_plural, init_germanic_plural): + Update. + * dcigettext.c (_nl_find_msg): Optimize for space. + (plural_eval): Recognize comparison and '!' operators. Optimize for + space. + + * dcigettext.c (transcmp): New declaration. 2001-03-10 Bruno Haible diff --git a/intl/dcigettext.c b/intl/dcigettext.c index ba93fb303..937c0fdee 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -243,6 +243,7 @@ static void *root; # endif /* Function to compare two entries in the table of known translations. */ +static int transcmp PARAMS ((const void *p1, const void *p2)); static int transcmp (p1, p2) const void *p1; @@ -685,14 +686,15 @@ _nl_find_msg (domain_file, msgid, lengthp) nls_uint32 hash_val = hash_string (msgid); nls_uint32 idx = hash_val % domain->hash_size; nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); - nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]); - - if (nstr == 0) - /* Hash table entry is empty. */ - return NULL; while (1) { + nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]); + + if (nstr == 0) + /* Hash table entry is empty. */ + return NULL; + /* Compare msgid with the original string at index nstr-1. We compare the lengths with >=, not ==, because plural entries are represented by strings with an embedded NUL. */ @@ -710,11 +712,6 @@ _nl_find_msg (domain_file, msgid, lengthp) idx -= domain->hash_size - incr; else idx += incr; - - nstr = W (domain->must_swap, domain->hash_tab[idx]); - if (nstr == 0) - /* Hash table entry is empty. */ - return NULL; } /* NOTREACHED */ } @@ -988,57 +985,74 @@ plural_eval (pexp, n) struct expression *pexp; unsigned long int n; { - switch (pexp->operation) + switch (pexp->nargs) { - case var: - return n; - case num: - return pexp->val.num; - case lnot: - return ! plural_eval (pexp->val.args1.right, n); - case mult: - return (plural_eval (pexp->val.args2.left, n) - * plural_eval (pexp->val.args2.right, n)); - case divide: - return (plural_eval (pexp->val.args2.left, n) - / plural_eval (pexp->val.args2.right, n)); - case module: - return (plural_eval (pexp->val.args2.left, n) - % plural_eval (pexp->val.args2.right, n)); - case plus: - return (plural_eval (pexp->val.args2.left, n) - + plural_eval (pexp->val.args2.right, n)); - case minus: - return (plural_eval (pexp->val.args2.left, n) - - plural_eval (pexp->val.args2.right, n)); - case less_than: - return (plural_eval (pexp->val.args2.left, n) - < plural_eval (pexp->val.args2.right, n)); - case greater_than: - return (plural_eval (pexp->val.args2.left, n) - > plural_eval (pexp->val.args2.right, n)); - case less_or_equal: - return (plural_eval (pexp->val.args2.left, n) - <= plural_eval (pexp->val.args2.right, n)); - case greater_or_equal: - return (plural_eval (pexp->val.args2.left, n) - >= plural_eval (pexp->val.args2.right, n)); - case equal: - return (plural_eval (pexp->val.args2.left, n) - == plural_eval (pexp->val.args2.right, n)); - case not_equal: - return (plural_eval (pexp->val.args2.left, n) - != plural_eval (pexp->val.args2.right, n)); - case land: - return (plural_eval (pexp->val.args2.left, n) - && plural_eval (pexp->val.args2.right, n)); - case lor: - return (plural_eval (pexp->val.args2.left, n) - || plural_eval (pexp->val.args2.right, n)); - case qmop: - return (plural_eval (pexp->val.args3.bexp, n) - ? plural_eval (pexp->val.args3.tbranch, n) - : plural_eval (pexp->val.args3.fbranch, n)); + case 0: + switch (pexp->operation) + { + case var: + return n; + case num: + return pexp->val.num; + default: + break; + } + /* NOTREACHED */ + break; + case 1: + { + /* pexp->operation must be lnot. */ + unsigned long int arg = plural_eval (pexp->val.args[0], n); + return ! arg; + } + case 2: + { + unsigned long int leftarg = plural_eval (pexp->val.args[0], n); + if (pexp->operation == lor) + return leftarg || plural_eval (pexp->val.args[1], n); + else if (pexp->operation == land) + return leftarg && plural_eval (pexp->val.args[1], n); + else + { + unsigned long int rightarg = plural_eval (pexp->val.args[1], n); + + switch (pexp->operation) + { + case mult: + return leftarg * rightarg; + case divide: + return leftarg / rightarg; + case module: + return leftarg % rightarg; + case plus: + return leftarg + rightarg; + case minus: + return leftarg - rightarg; + case less_than: + return leftarg < rightarg; + case greater_than: + return leftarg > rightarg; + case less_or_equal: + return leftarg <= rightarg; + case greater_or_equal: + return leftarg >= rightarg; + case equal: + return leftarg == rightarg; + case not_equal: + return leftarg != rightarg; + default: + break; + } + } + /* NOTREACHED */ + break; + } + case 3: + { + /* pexp->operation must be qmop. */ + unsigned long int boolarg = plural_eval (pexp->val.args[0], n); + return plural_eval (pexp->val.args[boolarg ? 1 : 2], n); + } } /* NOTREACHED */ return 0; diff --git a/intl/gettextP.h b/intl/gettextP.h index 715b04d99..c7f465549 100644 --- a/intl/gettextP.h +++ b/intl/gettextP.h @@ -75,11 +75,15 @@ SWAP (i) plural form. */ struct expression { + int nargs; /* Number of arguments. */ enum operator { + /* Without arguments: */ var, /* The variable "n". */ num, /* Decimal number. */ + /* Unary operators: */ lnot, /* Logical NOT. */ + /* Binary operators: */ mult, /* Multiplication. */ divide, /* Division. */ module, /* Module operation. */ @@ -89,30 +93,17 @@ struct expression greater_than, /* Comparison. */ less_or_equal, /* Comparison. */ greater_or_equal, /* Comparison. */ - equal, /* Comparison for equality. */ - not_equal, /* Comparison for inequality. */ + equal, /* Comparision for equality. */ + not_equal, /* Comparision for inequality. */ land, /* Logical AND. */ lor, /* Logical OR. */ + /* Ternary operators: */ qmop /* Question mark operator. */ } operation; union { unsigned long int num; /* Number value for `num'. */ - struct - { - struct expression *right; /* Subexpression in unary operation. */ - } args1; - struct - { - struct expression *left; /* Left expression in binary operation. */ - struct expression *right; /* Right expression in binary operation. */ - } args2; - struct - { - struct expression *bexp; /* Boolean expression in ?: operation. */ - struct expression *tbranch; /* True-branch in ?: operation. */ - struct expression *fbranch; /* False-branch in ?: operation. */ - } args3; + struct expression *args[3]; /* Up to three arguments. */ } val; }; diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c index a4a1cba6c..7ce30892c 100644 --- a/intl/loadmsgcat.c +++ b/intl/loadmsgcat.c @@ -138,10 +138,12 @@ int _nl_msg_cat_cntr; form determination. It represents the expression "n != 1". */ static const struct expression plvar = { + .nargs = 0, .operation = var, }; static const struct expression plone = { + .nargs = 0, .operation = num, .val = { @@ -150,13 +152,14 @@ static const struct expression plone = }; static struct expression germanic_plural = { + .nargs = 2, .operation = not_equal, .val = { - .args2 = + .args = { - .left = (struct expression *) &plvar, - .right = (struct expression *) &plone + [0] = (struct expression *) &plvar, + [1] = (struct expression *) &plone } } }; @@ -177,14 +180,17 @@ init_germanic_plural () { if (plone.val.num == 0) { + plvar.nargs = 0; plvar.operation = var; + plone.nargs = 0; plone.operation = num; plone.val.num = 1; + germanic_plural.nargs = 2; germanic_plural.operation = not_equal; - germanic_plural.val.args2.left = &plvar; - germanic_plural.val.args2.right = &plone; + germanic_plural.val.args[0] = &plvar; + germanic_plural.val.args[1] = &plone; } } @@ -441,7 +447,7 @@ _nl_load_domain (domain_file) nplurals += 9; while (*nplurals != '\0' && isspace (*nplurals)) ++nplurals; -#ifdef HAVE_STRTOUL +#if defined HAVE_STRTOUL || defined _LIBC n = strtoul (nplurals, &endp, 10); #else for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++) diff --git a/intl/plural.y b/intl/plural.y index 20fb60c81..f50f8648d 100644 --- a/intl/plural.y +++ b/intl/plural.y @@ -43,37 +43,124 @@ %union { unsigned long int num; + enum operator op; struct expression *exp; } %{ /* Prototypes for local functions. */ -static struct expression *new_exp_0 PARAMS ((enum operator op)); -static struct expression *new_exp_1 PARAMS ((enum operator op, - struct expression *right)); +static struct expression *new_exp PARAMS ((int nargs, enum operator op, + struct expression * const *args)); +static inline struct expression *new_exp_0 PARAMS ((enum operator op)); +static inline struct expression *new_exp_1 PARAMS ((enum operator op, + struct expression *right)); static struct expression *new_exp_2 PARAMS ((enum operator op, struct expression *left, struct expression *right)); -static struct expression *new_exp_3 PARAMS ((enum operator op, - struct expression *bexp, - struct expression *tbranch, - struct expression *fbranch)); +static inline struct expression *new_exp_3 PARAMS ((enum operator op, + struct expression *bexp, + struct expression *tbranch, + struct expression *fbranch)); static int yylex PARAMS ((YYSTYPE *lval, const char **pexp)); static void yyerror PARAMS ((const char *str)); + +/* Allocation of expressions. */ + +static struct expression * +new_exp (nargs, op, args) + int nargs; + enum operator op; + struct expression * const *args; +{ + int i; + struct expression *newp; + + /* If any of the argument could not be malloc'ed, just return NULL. */ + for (i = nargs - 1; i >= 0; i--) + if (args[i] == NULL) + goto fail; + + /* Allocate a new expression. */ + newp = (struct expression *) malloc (sizeof (*newp)); + if (newp != NULL) + { + newp->nargs = nargs; + newp->operation = op; + for (i = nargs - 1; i >= 0; i--) + newp->val.args[i] = args[i]; + return newp; + } + + fail: + for (i = nargs - 1; i >= 0; i--) + FREE_EXPRESSION (args[i]); + + return NULL; +} + +static inline struct expression * +new_exp_0 (op) + enum operator op; +{ + return new_exp (0, op, NULL); +} + +static inline struct expression * +new_exp_1 (op, right) + enum operator op; + struct expression *right; +{ + struct expression *args[1]; + + args[0] = right; + return new_exp (1, op, args); +} + +static struct expression * +new_exp_2 (op, left, right) + enum operator op; + struct expression *left; + struct expression *right; +{ + struct expression *args[2]; + + args[0] = left; + args[1] = right; + return new_exp (2, op, args); +} + +static inline struct expression * +new_exp_3 (op, bexp, tbranch, fbranch) + enum operator op; + struct expression *bexp; + struct expression *tbranch; + struct expression *fbranch; +{ + struct expression *args[3]; + + args[0] = bexp; + args[1] = tbranch; + args[2] = fbranch; + return new_exp (3, op, args); +} + %} /* This declares that all operators have the same associativity and the precedence order as in C. See [Harbison, Steele: C, A Reference Manual]. - There is no unary minus and no bitwise operators. */ -%right '?' /* ? */ -%left '|' /* || */ -%left '&' /* && */ -%left EQ, NE /* == != */ -%left '<', '>', LE, GE /* < > <= >= */ -%left '+', '-' /* + - */ -%left '*', '/', '%' /* * / % */ -%right '!' /* ! */ - + There is no unary minus and no bitwise operators. + Operators with the same syntactic behaviour have been merged into a single + token, to save space in the array generated by bison. */ +%right '?' /* ? */ +%left '|' /* || */ +%left '&' /* && */ +%left EQUOP2 /* == != */ +%left CMPOP2 /* < > <= >= */ +%left ADDOP2 /* + - */ +%left MULOP2 /* * / % */ +%right '!' /* ! */ + +%token EQUOP2 CMPOP2 ADDOP2 MULOP2 %token NUMBER %type exp @@ -81,194 +168,61 @@ static void yyerror PARAMS ((const char *str)); start: exp { + if ($1 == NULL) + YYABORT; ((struct parse_args *) arg)->res = $1; } ; exp: exp '?' exp ':' exp { - if (($$ = new_exp_3 (qmop, $1, $3, $5)) == NULL) - YYABORT + $$ = new_exp_3 (qmop, $1, $3, $5); } | exp '|' exp { - if (($$ = new_exp_2 (lor, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 (lor, $1, $3); } | exp '&' exp { - if (($$ = new_exp_2 (land, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 (land, $1, $3); } - | exp EQ exp + | exp EQUOP2 exp { - if (($$ = new_exp_2 (equal, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp NE exp + | exp CMPOP2 exp { - if (($$ = new_exp_2 (not_equal, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '<' exp + | exp ADDOP2 exp { - if (($$ = new_exp_2 (less_than, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '>' exp + | exp MULOP2 exp { - if (($$ = new_exp_2 (greater_than, $1, $3)) == NULL) - YYABORT - } - | exp LE exp - { - if (($$ = new_exp_2 (less_or_equal, $1, $3)) == NULL) - YYABORT - } - | exp GE exp - { - if (($$ = new_exp_2 (greater_or_equal, $1, $3)) == NULL) - YYABORT - } - | exp '+' exp - { - if (($$ = new_exp_2 (plus, $1, $3)) == NULL) - YYABORT - } - | exp '-' exp - { - if (($$ = new_exp_2 (minus, $1, $3)) == NULL) - YYABORT - } - | exp '*' exp - { - if (($$ = new_exp_2 (mult, $1, $3)) == NULL) - YYABORT - } - | exp '/' exp - { - if (($$ = new_exp_2 (divide, $1, $3)) == NULL) - YYABORT - } - | exp '%' exp - { - if (($$ = new_exp_2 (module, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } | '!' exp { - if (($$ = new_exp_1 (lnot, $2)) == NULL) - YYABORT + $$ = new_exp_1 (lnot, $2); } | 'n' { - if (($$ = new_exp_0 (var)) == NULL) - YYABORT + $$ = new_exp_0 (var); } | NUMBER { - if (($$ = new_exp_0 (num)) == NULL) - YYABORT; - $$->val.num = $1 + if (($$ = new_exp_0 (num)) != NULL) + $$->val.num = $1; } | '(' exp ')' { - $$ = $2 + $$ = $2; } ; %% -static struct expression * -new_exp_0 (op) - enum operator op; -{ - struct expression *newp = (struct expression *) malloc (sizeof (*newp)); - - if (newp != NULL) - newp->operation = op; - - return newp; -} - -static struct expression * -new_exp_1 (op, right) - enum operator op; - struct expression *right; -{ - struct expression *newp = NULL; - - if (right != NULL) - newp = (struct expression *) malloc (sizeof (*newp)); - - if (newp != NULL) - { - newp->operation = op; - newp->val.args1.right = right; - } - else - { - FREE_EXPRESSION (right); - } - - return newp; -} - -static struct expression * -new_exp_2 (op, left, right) - enum operator op; - struct expression *left; - struct expression *right; -{ - struct expression *newp = NULL; - - if (left != NULL && right != NULL) - newp = (struct expression *) malloc (sizeof (*newp)); - - if (newp != NULL) - { - newp->operation = op; - newp->val.args2.left = left; - newp->val.args2.right = right; - } - else - { - FREE_EXPRESSION (left); - FREE_EXPRESSION (right); - } - - return newp; -} - -static struct expression * -new_exp_3 (op, bexp, tbranch, fbranch) - enum operator op; - struct expression *bexp; - struct expression *tbranch; - struct expression *fbranch; -{ - struct expression *newp = NULL; - - if (bexp != NULL && tbranch != NULL && fbranch != NULL) - newp = (struct expression *) malloc (sizeof (*newp)); - - if (newp != NULL) - { - newp->operation = op; - newp->val.args3.bexp = bexp; - newp->val.args3.tbranch = tbranch; - newp->val.args3.fbranch = fbranch; - } - else - { - FREE_EXPRESSION (bexp); - FREE_EXPRESSION (tbranch); - FREE_EXPRESSION (fbranch); - } - - return newp; -} - void internal_function FREE_EXPRESSION (exp) @@ -278,37 +232,17 @@ FREE_EXPRESSION (exp) return; /* Handle the recursive case. */ - switch (exp->operation) + switch (exp->nargs) { - case qmop: - FREE_EXPRESSION (exp->val.args3.fbranch); - /* FREE_EXPRESSION (exp->val.args3.tbranch); */ - /* FREE_EXPRESSION (exp->val.args3.bexp); */ - /* break; */ - /* instead: FALLTHROUGH */ - - case mult: - case divide: - case module: - case plus: - case minus: - case less_than: - case greater_than: - case less_or_equal: - case greater_or_equal: - case equal: - case not_equal: - case land: - case lor: - FREE_EXPRESSION (exp->val.args2.right); - /* FREE_EXPRESSION (exp->val.args2.left); */ - /* break; */ - /* instead: FALLTHROUGH */ - - case lnot: - FREE_EXPRESSION (exp->val.args1.right); - break; - + case 3: + FREE_EXPRESSION (exp->val.args[2]); + /* FALLTHROUGH */ + case 2: + FREE_EXPRESSION (exp->val.args[1]); + /* FALLTHROUGH */ + case 1: + FREE_EXPRESSION (exp->val.args[0]); + /* FALLTHROUGH */ default: break; } @@ -361,7 +295,8 @@ yylex (lval, pexp) if (exp[0] == '=') { ++exp; - result = EQ; + lval->op = equal; + result = EQUOP2; } else result = YYERRCODE; @@ -371,7 +306,8 @@ yylex (lval, pexp) if (exp[0] == '=') { ++exp; - result = NE; + lval->op = not_equal; + result = EQUOP2; } break; @@ -387,24 +323,50 @@ yylex (lval, pexp) if (exp[0] == '=') { ++exp; - result = LE; + lval->op = less_or_equal; } + else + lval->op = less_than; + result = CMPOP2; break; case '>': if (exp[0] == '=') { ++exp; - result = GE; + lval->op = greater_or_equal; } + else + lval->op = greater_than; + result = CMPOP2; break; - case 'n': case '*': + lval->op = mult; + result = MULOP2; + break; + case '/': + lval->op = divide; + result = MULOP2; + break; + case '%': + lval->op = module; + result = MULOP2; + break; + case '+': + lval->op = plus; + result = ADDOP2; + break; + case '-': + lval->op = minus; + result = ADDOP2; + break; + + case 'n': case '?': case ':': case '(':