(new_exp): Take number of optional parameters in second parameter.
[kopensolaris-gnu/glibc.git] / intl / plural.y
1 %{
2 /* Expression parsing for plural form selection.
3    Copyright (C) 2000 Free Software Foundation, Inc.
4    Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library 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 the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "gettext.h"
24 #include "gettextP.h"
25
26 #define YYLEX_PARAM     &((struct parse_args *) arg)->cp
27 #define YYPARSE_PARAM   arg
28 %}
29 %pure_parser
30 %expect 10
31
32 %union {
33   unsigned long int num;
34   struct expression *exp;
35 }
36
37 %{
38 /* Prototypes for local functions.  */
39 static struct expression *new_exp (enum operator op, int n, ...);
40 static int yylex (YYSTYPE *lval, const char **pexp);
41 static void yyerror (const char *str);
42 %}
43
44 %left '?'
45 %left '|'
46 %left '&'
47 %left '=', '!'
48 %left '+', '-'
49 %left '*', '/', '%'
50 %token <num> NUMBER
51 %type <exp> exp
52
53 %%
54
55 start:    exp
56           {
57             ((struct parse_args *) arg)->res = $1;
58           }
59         ;
60
61 exp:      exp '?' exp ':' exp
62           {
63             if (($$ = new_exp (qmop, 3, $1, $3, $5)) == NULL)
64               YYABORT
65           }
66         | exp '|' exp
67           {
68             if (($$ = new_exp (lor, 2, $1, $3)) == NULL)
69               YYABORT
70           }
71         | exp '&' exp
72           {
73             if (($$ = new_exp (land, 2, $1, $3)) == NULL)
74               YYABORT
75           }
76         | exp '=' exp
77           {
78             if (($$ = new_exp (equal, 2, $1, $3)) == NULL)
79               YYABORT
80           }
81         | exp '!' exp
82           {
83             if (($$ = new_exp (not_equal, 2, $1, $3)) == NULL)
84               YYABORT
85           }
86         | exp '+' exp
87           {
88             if (($$ = new_exp (plus, 2, $1, $3)) == NULL)
89               YYABORT
90           }
91         | exp '-' exp
92           {
93             if (($$ = new_exp (minus, 2, $1, $3)) == NULL)
94               YYABORT
95           }
96         | exp '*' exp
97           {
98             if (($$ = new_exp (mult, 2, $1, $3)) == NULL)
99               YYABORT
100           }
101         | exp '/' exp
102           {
103             if (($$ = new_exp (divide, 2, $1, $3)) == NULL)
104               YYABORT
105           }
106         | exp '%' exp
107           {
108             if (($$ = new_exp (module, 2, $1, $3)) == NULL)
109               YYABORT
110           }
111         | 'n'
112           {
113             if (($$ = new_exp (var, 0)) == NULL)
114               YYABORT
115           }
116         | NUMBER
117           {
118             if (($$ = new_exp (num, 0)) == NULL)
119               YYABORT;
120             $$->val.num = $1
121           }
122         | '(' exp ')'
123           {
124             $$ = $2
125           }
126         ;
127
128 %%
129
130 static struct expression *
131 new_exp (enum operator op, int n, ...)
132 {
133   struct expression *newp = (struct expression *) calloc (1, sizeof (*newp));
134   va_list va;
135
136   va_start (va, n);
137
138   if (newp == NULL)
139     while (n-- > 0)
140       __gettext_free_exp (va_arg (va, struct expression *));
141   else
142     {
143       newp->operation = op;
144       if (n > 0)
145         {
146           newp->val.args3.bexp = va_arg (va, struct expression *);
147           newp->val.args3.tbranch = va_arg (va, struct expression *);
148
149           if (n > 2)
150             newp->val.args3.fbranch = va_arg (va, struct expression *);
151
152           if (newp->val.args3.bexp == NULL
153               || newp->val.args3.tbranch == NULL
154               || (n > 2 && newp->val.args3.fbranch == NULL))
155             {
156               __gettext_free_exp (newp);
157               newp = NULL;
158             }
159         }
160     }
161
162   va_end (va);
163
164   return newp;
165 }
166
167 void
168 internal_function
169 __gettext_free_exp (struct expression *exp)
170 {
171   if (exp == NULL)
172     return;
173
174   /* Handle the recursive case.  */
175   switch (exp->operation)
176     {
177     case qmop:
178       __gettext_free_exp (exp->val.args3.fbranch);
179       /* FALLTHROUGH */
180
181     case mult:
182     case divide:
183     case module:
184     case plus:
185     case minus:
186     case equal:
187     case not_equal:
188     case land:
189     case lor:
190       __gettext_free_exp (exp->val.args2.right);
191       __gettext_free_exp (exp->val.args2.left);
192       break;
193
194     default:
195       break;
196     }
197
198   free (exp);
199 }
200
201
202 static int
203 yylex (YYSTYPE *lval, const char **pexp)
204 {
205   const char *exp = *pexp;
206   int result;
207
208   while (1)
209     {
210       if (exp[0] == '\\' && exp[1] == '\n')
211         {
212           exp += 2;
213           continue;
214         }
215
216       if (exp[0] == '\0')
217         {
218           *pexp = exp;
219           return YYEOF;
220         }
221
222       if (exp[0] != ' ' && exp[0] != '\t')
223         break;
224
225       ++exp;
226     }
227
228   result = *exp++;
229   switch (result)
230     {
231     case '0' ... '9':
232       {
233         unsigned long int n = exp[-1] - '0';
234         while (exp[0] >= '0' && exp[0] <= '9')
235           {
236             n *= 10;
237             n += exp[0] - '0';
238             ++exp;
239           }
240         lval->num = n;
241         result = NUMBER;
242       }
243       break;
244
245     case '=':
246     case '!':
247       if (exp[0] == '=')
248         ++exp;
249       else
250         result = YYERRCODE;
251       break;
252
253     case '&':
254     case '|':
255       if (exp[0] == result)
256         ++exp;
257       else
258         result = YYERRCODE;
259       break;
260
261     case 'n':
262     case '*':
263     case '/':
264     case '%':
265     case '+':
266     case '-':
267     case '?':
268     case ':':
269     case '(':
270     case ')':
271       /* Nothing, just return the character.  */
272       break;
273
274     case ';':
275     case '\n':
276     case '\0':
277       /* Be safe and let the user call this function again.  */
278       --exp;
279       result = YYEOF;
280       break;
281
282     default:
283       result = YYERRCODE;
284 #if YYDEBUG != 0
285       --exp;
286 #endif
287       break;
288     }
289
290   *pexp = exp;
291
292   return result;
293 }
294
295
296 static void
297 yyerror (const char *str)
298 {
299   /* Do nothing.  We don't print error messages here.  */
300 }