Home | History | Annotate | Download | only in intl
      1 %{
      2 /* Expression parsing for plural form selection.
      3    Copyright (C) 2000, 2001 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
     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 struct expression *new_exp PARAMS ((int nargs, enum operator op,
     58 					   struct expression * const *args));
     59 static inline struct expression *new_exp_0 PARAMS ((enum operator op));
     60 static inline struct expression *new_exp_1 PARAMS ((enum operator op,
     61 						   struct expression *right));
     62 static struct expression *new_exp_2 PARAMS ((enum operator op,
     63 					     struct expression *left,
     64 					     struct expression *right));
     65 static inline struct expression *new_exp_3 PARAMS ((enum operator op,
     66 						   struct expression *bexp,
     67 						   struct expression *tbranch,
     68 						   struct expression *fbranch));
     69 static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
     70 static void yyerror PARAMS ((const char *str));
     71 
     72 /* Allocation of expressions.  */
     73 
     74 static struct expression *
     75 new_exp (nargs, op, args)
     76      int nargs;
     77      enum operator op;
     78      struct expression * const *args;
     79 {
     80   int i;
     81   struct expression *newp;
     82 
     83   /* If any of the argument could not be malloc'ed, just return NULL.  */
     84   for (i = nargs - 1; i >= 0; i--)
     85     if (args[i] == NULL)
     86       goto fail;
     87 
     88   /* Allocate a new expression.  */
     89   newp = (struct expression *) malloc (sizeof (*newp));
     90   if (newp != NULL)
     91     {
     92       newp->nargs = nargs;
     93       newp->operation = op;
     94       for (i = nargs - 1; i >= 0; i--)
     95 	newp->val.args[i] = args[i];
     96       return newp;
     97     }
     98 
     99  fail:
    100   for (i = nargs - 1; i >= 0; i--)
    101     FREE_EXPRESSION (args[i]);
    102 
    103   return NULL;
    104 }
    105 
    106 static inline struct expression *
    107 new_exp_0 (op)
    108      enum operator op;
    109 {
    110   return new_exp (0, op, NULL);
    111 }
    112 
    113 static inline struct expression *
    114 new_exp_1 (op, right)
    115      enum operator op;
    116      struct expression *right;
    117 {
    118   struct expression *args[1];
    119 
    120   args[0] = right;
    121   return new_exp (1, op, args);
    122 }
    123 
    124 static struct expression *
    125 new_exp_2 (op, left, right)
    126      enum operator op;
    127      struct expression *left;
    128      struct expression *right;
    129 {
    130   struct expression *args[2];
    131 
    132   args[0] = left;
    133   args[1] = right;
    134   return new_exp (2, op, args);
    135 }
    136 
    137 static inline struct expression *
    138 new_exp_3 (op, bexp, tbranch, fbranch)
    139      enum operator op;
    140      struct expression *bexp;
    141      struct expression *tbranch;
    142      struct expression *fbranch;
    143 {
    144   struct expression *args[3];
    145 
    146   args[0] = bexp;
    147   args[1] = tbranch;
    148   args[2] = fbranch;
    149   return new_exp (3, op, args);
    150 }
    151 
    152 %}
    153 
    154 /* This declares that all operators have the same associativity and the
    155    precedence order as in C.  See [Harbison, Steele: C, A Reference Manual].
    156    There is no unary minus and no bitwise operators.
    157    Operators with the same syntactic behaviour have been merged into a single
    158    token, to save space in the array generated by bison.  */
    159 %right '?'		/*   ?		*/
    160 %left '|'		/*   ||		*/
    161 %left '&'		/*   &&		*/
    162 %left EQUOP2		/*   == !=	*/
    163 %left CMPOP2		/*   < > <= >=	*/
    164 %left ADDOP2		/*   + -	*/
    165 %left MULOP2		/*   * / %	*/
    166 %right '!'		/*   !		*/
    167 
    168 %token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2
    169 %token <num> NUMBER
    170 %type <exp> exp
    171 
    172 %%
    173 
    174 start:	  exp
    175 	  {
    176 	    if ($1 == NULL)
    177 	      YYABORT;
    178 	    ((struct parse_args *) arg)->res = $1;
    179 	  }
    180 	;
    181 
    182 exp:	  exp '?' exp ':' exp
    183 	  {
    184 	    $$ = new_exp_3 (qmop, $1, $3, $5);
    185 	  }
    186 	| exp '|' exp
    187 	  {
    188 	    $$ = new_exp_2 (lor, $1, $3);
    189 	  }
    190 	| exp '&' exp
    191 	  {
    192 	    $$ = new_exp_2 (land, $1, $3);
    193 	  }
    194 	| exp EQUOP2 exp
    195 	  {
    196 	    $$ = new_exp_2 ($2, $1, $3);
    197 	  }
    198 	| exp CMPOP2 exp
    199 	  {
    200 	    $$ = new_exp_2 ($2, $1, $3);
    201 	  }
    202 	| exp ADDOP2 exp
    203 	  {
    204 	    $$ = new_exp_2 ($2, $1, $3);
    205 	  }
    206 	| exp MULOP2 exp
    207 	  {
    208 	    $$ = new_exp_2 ($2, $1, $3);
    209 	  }
    210 	| '!' exp
    211 	  {
    212 	    $$ = new_exp_1 (lnot, $2);
    213 	  }
    214 	| 'n'
    215 	  {
    216 	    $$ = new_exp_0 (var);
    217 	  }
    218 	| NUMBER
    219 	  {
    220 	    if (($$ = new_exp_0 (num)) != NULL)
    221 	      $$->val.num = $1;
    222 	  }
    223 	| '(' exp ')'
    224 	  {
    225 	    $$ = $2;
    226 	  }
    227 	;
    228 
    229 %%
    230 
    231 void
    232 internal_function
    233 FREE_EXPRESSION (exp)
    234      struct expression *exp;
    235 {
    236   if (exp == NULL)
    237     return;
    238 
    239   /* Handle the recursive case.  */
    240   switch (exp->nargs)
    241     {
    242     case 3:
    243       FREE_EXPRESSION (exp->val.args[2]);
    244       /* FALLTHROUGH */
    245     case 2:
    246       FREE_EXPRESSION (exp->val.args[1]);
    247       /* FALLTHROUGH */
    248     case 1:
    249       FREE_EXPRESSION (exp->val.args[0]);
    250       /* FALLTHROUGH */
    251     default:
    252       break;
    253     }
    254 
    255   free (exp);
    256 }
    257 
    258 
    259 static int
    260 yylex (lval, pexp)
    261      YYSTYPE *lval;
    262      const char **pexp;
    263 {
    264   const char *exp = *pexp;
    265   int result;
    266 
    267   while (1)
    268     {
    269       if (exp[0] == '\0')
    270 	{
    271 	  *pexp = exp;
    272 	  return YYEOF;
    273 	}
    274 
    275       if (exp[0] != ' ' && exp[0] != '\t')
    276 	break;
    277 
    278       ++exp;
    279     }
    280 
    281   result = *exp++;
    282   switch (result)
    283     {
    284     case '0': case '1': case '2': case '3': case '4':
    285     case '5': case '6': case '7': case '8': case '9':
    286       {
    287 	unsigned long int n = result - '0';
    288 	while (exp[0] >= '0' && exp[0] <= '9')
    289 	  {
    290 	    n *= 10;
    291 	    n += exp[0] - '0';
    292 	    ++exp;
    293 	  }
    294 	lval->num = n;
    295 	result = NUMBER;
    296       }
    297       break;
    298 
    299     case '=':
    300       if (exp[0] == '=')
    301 	{
    302 	  ++exp;
    303 	  lval->op = equal;
    304 	  result = EQUOP2;
    305 	}
    306       else
    307 	result = YYERRCODE;
    308       break;
    309 
    310     case '!':
    311       if (exp[0] == '=')
    312 	{
    313 	  ++exp;
    314 	  lval->op = not_equal;
    315 	  result = EQUOP2;
    316 	}
    317       break;
    318 
    319     case '&':
    320     case '|':
    321       if (exp[0] == result)
    322 	++exp;
    323       else
    324 	result = YYERRCODE;
    325       break;
    326 
    327     case '<':
    328       if (exp[0] == '=')
    329 	{
    330 	  ++exp;
    331 	  lval->op = less_or_equal;
    332 	}
    333       else
    334 	lval->op = less_than;
    335       result = CMPOP2;
    336       break;
    337 
    338     case '>':
    339       if (exp[0] == '=')
    340 	{
    341 	  ++exp;
    342 	  lval->op = greater_or_equal;
    343 	}
    344       else
    345 	lval->op = greater_than;
    346       result = CMPOP2;
    347       break;
    348 
    349     case '*':
    350       lval->op = mult;
    351       result = MULOP2;
    352       break;
    353 
    354     case '/':
    355       lval->op = divide;
    356       result = MULOP2;
    357       break;
    358 
    359     case '%':
    360       lval->op = module;
    361       result = MULOP2;
    362       break;
    363 
    364     case '+':
    365       lval->op = plus;
    366       result = ADDOP2;
    367       break;
    368 
    369     case '-':
    370       lval->op = minus;
    371       result = ADDOP2;
    372       break;
    373 
    374     case 'n':
    375     case '?':
    376     case ':':
    377     case '(':
    378     case ')':
    379       /* Nothing, just return the character.  */
    380       break;
    381 
    382     case ';':
    383     case '\n':
    384     case '\0':
    385       /* Be safe and let the user call this function again.  */
    386       --exp;
    387       result = YYEOF;
    388       break;
    389 
    390     default:
    391       result = YYERRCODE;
    392 #if YYDEBUG != 0
    393       --exp;
    394 #endif
    395       break;
    396     }
    397 
    398   *pexp = exp;
    399 
    400   return result;
    401 }
    402 
    403 
    404 static void
    405 yyerror (str)
    406      const char *str;
    407 {
    408   /* Do nothing.  We don't print error messages here.  */
    409 }
    410