diff options
Diffstat (limited to 'intl/plural.y')
-rw-r--r-- | intl/plural.y | 328 |
1 files changed, 214 insertions, 114 deletions
diff --git a/intl/plural.y b/intl/plural.y index f14dc29fd3..e85f7b8a65 100644 --- a/intl/plural.y +++ b/intl/plural.y @@ -22,11 +22,20 @@ # include <config.h> #endif -#include <stdarg.h> #include <stdlib.h> -#include "gettext.h" #include "gettextP.h" +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define FREE_EXPRESSION __gettext_free_exp +#else +# define FREE_EXPRESSION gettext_free_exp__ +# define __gettextparse gettextparse__ +#endif + #define YYLEX_PARAM &((struct parse_args *) arg)->cp #define YYPARSE_PARAM arg %} @@ -35,22 +44,124 @@ %union { unsigned long int num; + enum operator op; struct expression *exp; } %{ /* Prototypes for local functions. */ -static struct expression *new_exp (enum operator op, int n, ...); -static int yylex (YYSTYPE *lval, const char **pexp); -static void yyerror (const char *str); +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 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); +} + %} -%left '?' -%left '|' -%left '&' -%left '=', '!' -%left '+', '-' -%left '*', '/', '%' +/* 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. + 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 <op> EQUOP2 CMPOP2 ADDOP2 MULOP2 %token <num> NUMBER %type <exp> exp @@ -58,143 +169,81 @@ static void yyerror (const char *str); start: exp { + if ($1 == NULL) + YYABORT; ((struct parse_args *) arg)->res = $1; } ; exp: exp '?' exp ':' exp { - if (($$ = new_exp (qmop, 3, $1, $3, $5)) == NULL) - YYABORT + $$ = new_exp_3 (qmop, $1, $3, $5); } | exp '|' exp { - if (($$ = new_exp (lor, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 (lor, $1, $3); } | exp '&' exp { - if (($$ = new_exp (land, 2, $1, $3)) == NULL) - YYABORT - } - | exp '=' exp - { - if (($$ = new_exp (equal, 2, $1, $3)) == NULL) - YYABORT - } - | exp '!' exp - { - if (($$ = new_exp (not_equal, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 (land, $1, $3); } - | exp '+' exp + | exp EQUOP2 exp { - if (($$ = new_exp (plus, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '-' exp + | exp CMPOP2 exp { - if (($$ = new_exp (minus, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '*' exp + | exp ADDOP2 exp { - if (($$ = new_exp (mult, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '/' exp + | exp MULOP2 exp { - if (($$ = new_exp (divide, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_2 ($2, $1, $3); } - | exp '%' exp + | '!' exp { - if (($$ = new_exp (module, 2, $1, $3)) == NULL) - YYABORT + $$ = new_exp_1 (lnot, $2); } | 'n' { - if (($$ = new_exp (var, 0)) == NULL) - YYABORT + $$ = new_exp_0 (var); } | NUMBER { - if (($$ = new_exp (num, 0)) == NULL) - YYABORT; - $$->val.num = $1 + if (($$ = new_exp_0 (num)) != NULL) + $$->val.num = $1; } | '(' exp ')' { - $$ = $2 + $$ = $2; } ; %% -static struct expression * -new_exp (enum operator op, int n, ...) -{ - struct expression *newp = (struct expression *) calloc (1, sizeof (*newp)); - va_list va; - - va_start (va, n); - - if (newp == NULL) - while (n-- > 0) - __gettext_free_exp (va_arg (va, struct expression *)); - else - { - newp->operation = op; - if (n > 0) - { - newp->val.args3.bexp = va_arg (va, struct expression *); - newp->val.args3.tbranch = va_arg (va, struct expression *); - - if (n > 2) - newp->val.args3.fbranch = va_arg (va, struct expression *); - - if (newp->val.args3.bexp == NULL - || newp->val.args3.tbranch == NULL - || (n > 2 && newp->val.args3.fbranch == NULL)) - { - __gettext_free_exp (newp); - newp = NULL; - } - } - } - - va_end (va); - - return newp; -} - void internal_function -__gettext_free_exp (struct expression *exp) +FREE_EXPRESSION (exp) + struct expression *exp; { if (exp == NULL) return; /* Handle the recursive case. */ - switch (exp->operation) + switch (exp->nargs) { - case qmop: - __gettext_free_exp (exp->val.args3.fbranch); + 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 */ - - case mult: - case divide: - case module: - case plus: - case minus: - case equal: - case not_equal: - case land: - case lor: - __gettext_free_exp (exp->val.args2.right); - __gettext_free_exp (exp->val.args2.left); - break; - default: break; } @@ -204,19 +253,15 @@ __gettext_free_exp (struct expression *exp) static int -yylex (YYSTYPE *lval, const char **pexp) +yylex (lval, pexp) + YYSTYPE *lval; + const char **pexp; { const char *exp = *pexp; int result; while (1) { - if (exp[0] == '\\' && exp[1] == '\n') - { - exp += 2; - continue; - } - if (exp[0] == '\0') { *pexp = exp; @@ -248,13 +293,25 @@ yylex (YYSTYPE *lval, const char **pexp) break; case '=': - case '!': if (exp[0] == '=') - ++exp; + { + ++exp; + lval->op = equal; + result = EQUOP2; + } else result = YYERRCODE; break; + case '!': + if (exp[0] == '=') + { + ++exp; + lval->op = not_equal; + result = EQUOP2; + } + break; + case '&': case '|': if (exp[0] == result) @@ -263,12 +320,54 @@ yylex (YYSTYPE *lval, const char **pexp) result = YYERRCODE; break; - case 'n': + case '<': + if (exp[0] == '=') + { + ++exp; + lval->op = less_or_equal; + } + else + lval->op = less_than; + result = CMPOP2; + break; + + case '>': + if (exp[0] == '=') + { + ++exp; + lval->op = greater_or_equal; + } + else + lval->op = greater_than; + result = CMPOP2; + break; + 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 '(': @@ -299,7 +398,8 @@ yylex (YYSTYPE *lval, const char **pexp) static void -yyerror (const char *str) +yyerror (str) + const char *str; { /* Do nothing. We don't print error messages here. */ } |