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