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