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