Rocco Rutte:
[apps/madmutt.git] / intl / plural.y
1 %{
2 /* Expression parsing for plural form selection.
3    Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc.
4    Written by Ulrich Drepper <drepper@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 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 }