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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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.  */
57static int yylex (YYSTYPE *lval, const char **pexp);
58static void yyerror (const char *str);
59
60/* Allocation of expressions.  */
61
62static struct expression *
63new_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
91static inline struct expression *
92new_exp_0 (enum operator op)
93{
94  return new_exp (0, op, NULL);
95}
96
97static inline struct expression *
98new_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
106static struct expression *
107new_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
116static inline struct expression *
117new_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
150start:	  exp
151	  {
152	    if ($1 == NULL)
153	      YYABORT;
154	    ((struct parse_args *) arg)->res = $1;
155	  }
156	;
157
158exp:	  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
207void
208internal_function
209FREE_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
234static int
235yylex (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
377static void
378yyerror (const char *str)
379{
380  /* Do nothing.  We don't print error messages here.  */
381}
382