Home | History | Annotate | Download | only in intl
      1 %{
      2 /* Expression parsing for plural form selection.
      3    Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc.
      4    Written by Ulrich Drepper <drepper (at) cygnus.com>, 2000.
      5 
      6    This program is free software; you can redistribute it and/or modify it
      7    under the terms of the GNU Library General Public License as published
      8    by the Free Software Foundation; either version 2, or (at your option)
      9    any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14    Library General Public License for more details.
     15 
     16    You should have received a copy of the GNU Library General Public
     17    License along with this program; if not, write to the Free Software
     18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     19    USA.  */
     20 
     21 /* The bison generated parser uses alloca.  AIX 3 forces us to put this
     22    declaration at the beginning of the file.  The declaration in bison's
     23    skeleton file comes too late.  This must come before <config.h>
     24    because <config.h> may include arbitrary system headers.  */
     25 #if defined _AIX && !defined __GNUC__
     26  #pragma alloca
     27 #endif
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include <stddef.h>
     34 #include <stdlib.h>
     35 #include "plural-exp.h"
     36 
     37 /* The main function generated by the parser is called __gettextparse,
     38    but we want it to be called PLURAL_PARSE.  */
     39 #ifndef _LIBC
     40 # define __gettextparse PLURAL_PARSE
     41 #endif
     42 
     43 #define YYLEX_PARAM	&((struct parse_args *) arg)->cp
     44 #define YYPARSE_PARAM	arg
     45 %}
     46 %pure_parser
     47 %expect 7
     48 
     49 %union {
     50   unsigned long int num;
     51   enum operator op;
     52   struct expression *exp;
     53 }
     54 
     55 %{
     56 /* Prototypes for local functions.  */
     57 static int yylex (YYSTYPE *lval, const char **pexp);
     58 static void yyerror (const char *str);
     59 
     60 /* Allocation of expressions.  */
     61 
     62 static struct expression *
     63 new_exp (int nargs, enum operator op, struct expression * const *args)
     64 {
     65   int i;
     66   struct expression *newp;
     67 
     68   /* If any of the argument could not be malloc'ed, just return NULL.  */
     69   for (i = nargs - 1; i >= 0; i--)
     70     if (args[i] == NULL)
     71       goto fail;
     72 
     73   /* Allocate a new expression.  */
     74   newp = (struct expression *) malloc (sizeof (*newp));
     75   if (newp != NULL)
     76     {
     77       newp->nargs = nargs;
     78       newp->operation = op;
     79       for (i = nargs - 1; i >= 0; i--)
     80 	newp->val.args[i] = args[i];
     81       return newp;
     82     }
     83 
     84  fail:
     85   for (i = nargs - 1; i >= 0; i--)
     86     FREE_EXPRESSION (args[i]);
     87 
     88   return NULL;
     89 }
     90 
     91 static inline struct expression *
     92 new_exp_0 (enum operator op)
     93 {
     94   return new_exp (0, op, NULL);
     95 }
     96 
     97 static inline struct expression *
     98 new_exp_1 (enum operator op, struct expression *right)
     99 {
    100   struct expression *args[1];
    101 
    102   args[0] = right;
    103   return new_exp (1, op, args);
    104 }
    105 
    106 static struct expression *
    107 new_exp_2 (enum operator op, struct expression *left, struct expression *right)
    108 {
    109   struct expression *args[2];
    110 
    111   args[0] = left;
    112   args[1] = right;
    113   return new_exp (2, op, args);
    114 }
    115 
    116 static inline struct expression *
    117 new_exp_3 (enum operator op, struct expression *bexp,
    118 	   struct expression *tbranch, struct expression *fbranch)
    119 {
    120   struct expression *args[3];
    121 
    122   args[0] = bexp;
    123   args[1] = tbranch;
    124   args[2] = fbranch;
    125   return new_exp (3, op, args);
    126 }
    127 
    128 %}
    129 
    130 /* This declares that all operators have the same associativity and the
    131    precedence order as in C.  See [Harbison, Steele: C, A Reference Manual].
    132    There is no unary minus and no bitwise operators.
    133    Operators with the same syntactic behaviour have been merged into a single
    134    token, to save space in the array generated by bison.  */
    135 %right '?'		/*   ?		*/
    136 %left '|'		/*   ||		*/
    137 %left '&'		/*   &&		*/
    138 %left EQUOP2		/*   == !=	*/
    139 %left CMPOP2		/*   < > <= >=	*/
    140 %left ADDOP2		/*   + -	*/
    141 %left MULOP2		/*   * / %	*/
    142 %right '!'		/*   !		*/
    143 
    144 %token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2
    145 %token <num> NUMBER
    146 %type <exp> exp
    147 
    148 %%
    149 
    150 start:	  exp
    151 	  {
    152 	    if ($1 == NULL)
    153 	      YYABORT;
    154 	    ((struct parse_args *) arg)->res = $1;
    155 	  }
    156 	;
    157 
    158 exp:	  exp '?' exp ':' exp
    159 	  {
    160 	    $$ = new_exp_3 (qmop, $1, $3, $5);
    161 	  }
    162 	| exp '|' exp
    163 	  {
    164 	    $$ = new_exp_2 (lor, $1, $3);
    165 	  }
    166 	| exp '&' exp
    167 	  {
    168 	    $$ = new_exp_2 (land, $1, $3);
    169 	  }
    170 	| exp EQUOP2 exp
    171 	  {
    172 	    $$ = new_exp_2 ($2, $1, $3);
    173 	  }
    174 	| exp CMPOP2 exp
    175 	  {
    176 	    $$ = new_exp_2 ($2, $1, $3);
    177 	  }
    178 	| exp ADDOP2 exp
    179 	  {
    180 	    $$ = new_exp_2 ($2, $1, $3);
    181 	  }
    182 	| exp MULOP2 exp
    183 	  {
    184 	    $$ = new_exp_2 ($2, $1, $3);
    185 	  }
    186 	| '!' exp
    187 	  {
    188 	    $$ = new_exp_1 (lnot, $2);
    189 	  }
    190 	| 'n'
    191 	  {
    192 	    $$ = new_exp_0 (var);
    193 	  }
    194 	| NUMBER
    195 	  {
    196 	    if (($$ = new_exp_0 (num)) != NULL)
    197 	      $$->val.num = $1;
    198 	  }
    199 	| '(' exp ')'
    200 	  {
    201 	    $$ = $2;
    202 	  }
    203 	;
    204 
    205 %%
    206 
    207 void
    208 internal_function
    209 FREE_EXPRESSION (struct expression *exp)
    210 {
    211   if (exp == NULL)
    212     return;
    213 
    214   /* Handle the recursive case.  */
    215   switch (exp->nargs)
    216     {
    217     case 3:
    218       FREE_EXPRESSION (exp->val.args[2]);
    219       /* FALLTHROUGH */
    220     case 2:
    221       FREE_EXPRESSION (exp->val.args[1]);
    222       /* FALLTHROUGH */
    223     case 1:
    224       FREE_EXPRESSION (exp->val.args[0]);
    225       /* FALLTHROUGH */
    226     default:
    227       break;
    228     }
    229 
    230   free (exp);
    231 }
    232 
    233 
    234 static int
    235 yylex (YYSTYPE *lval, const char **pexp)
    236 {
    237   const char *exp = *pexp;
    238   int result;
    239 
    240   while (1)
    241     {
    242       if (exp[0] == '\0')
    243 	{
    244 	  *pexp = exp;
    245 	  return YYEOF;
    246 	}
    247 
    248       if (exp[0] != ' ' && exp[0] != '\t')
    249 	break;
    250 
    251       ++exp;
    252     }
    253 
    254   result = *exp++;
    255   switch (result)
    256     {
    257     case '0': case '1': case '2': case '3': case '4':
    258     case '5': case '6': case '7': case '8': case '9':
    259       {
    260 	unsigned long int n = result - '0';
    261 	while (exp[0] >= '0' && exp[0] <= '9')
    262 	  {
    263 	    n *= 10;
    264 	    n += exp[0] - '0';
    265 	    ++exp;
    266 	  }
    267 	lval->num = n;
    268 	result = NUMBER;
    269       }
    270       break;
    271 
    272     case '=':
    273       if (exp[0] == '=')
    274 	{
    275 	  ++exp;
    276 	  lval->op = equal;
    277 	  result = EQUOP2;
    278 	}
    279       else
    280 	result = YYERRCODE;
    281       break;
    282 
    283     case '!':
    284       if (exp[0] == '=')
    285 	{
    286 	  ++exp;
    287 	  lval->op = not_equal;
    288 	  result = EQUOP2;
    289 	}
    290       break;
    291 
    292     case '&':
    293     case '|':
    294       if (exp[0] == result)
    295 	++exp;
    296       else
    297 	result = YYERRCODE;
    298       break;
    299 
    300     case '<':
    301       if (exp[0] == '=')
    302 	{
    303 	  ++exp;
    304 	  lval->op = less_or_equal;
    305 	}
    306       else
    307 	lval->op = less_than;
    308       result = CMPOP2;
    309       break;
    310 
    311     case '>':
    312       if (exp[0] == '=')
    313 	{
    314 	  ++exp;
    315 	  lval->op = greater_or_equal;
    316 	}
    317       else
    318 	lval->op = greater_than;
    319       result = CMPOP2;
    320       break;
    321 
    322     case '*':
    323       lval->op = mult;
    324       result = MULOP2;
    325       break;
    326 
    327     case '/':
    328       lval->op = divide;
    329       result = MULOP2;
    330       break;
    331 
    332     case '%':
    333       lval->op = module;
    334       result = MULOP2;
    335       break;
    336 
    337     case '+':
    338       lval->op = plus;
    339       result = ADDOP2;
    340       break;
    341 
    342     case '-':
    343       lval->op = minus;
    344       result = ADDOP2;
    345       break;
    346 
    347     case 'n':
    348     case '?':
    349     case ':':
    350     case '(':
    351     case ')':
    352       /* Nothing, just return the character.  */
    353       break;
    354 
    355     case ';':
    356     case '\n':
    357     case '\0':
    358       /* Be safe and let the user call this function again.  */
    359       --exp;
    360       result = YYEOF;
    361       break;
    362 
    363     default:
    364       result = YYERRCODE;
    365 #if YYDEBUG != 0
    366       --exp;
    367 #endif
    368       break;
    369     }
    370 
    371   *pexp = exp;
    372 
    373   return result;
    374 }
    375 
    376 
    377 static void
    378 yyerror (const char *str)
    379 {
    380   /* Do nothing.  We don't print error messages here.  */
    381 }
    382