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 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.  */
57static struct expression *new_exp PARAMS ((int nargs, enum operator op,
58					   struct expression * const *args));
59static inline struct expression *new_exp_0 PARAMS ((enum operator op));
60static inline struct expression *new_exp_1 PARAMS ((enum operator op,
61						   struct expression *right));
62static struct expression *new_exp_2 PARAMS ((enum operator op,
63					     struct expression *left,
64					     struct expression *right));
65static inline struct expression *new_exp_3 PARAMS ((enum operator op,
66						   struct expression *bexp,
67						   struct expression *tbranch,
68						   struct expression *fbranch));
69static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
70static void yyerror PARAMS ((const char *str));
71
72/* Allocation of expressions.  */
73
74static struct expression *
75new_exp (nargs, op, args)
76     int nargs;
77     enum operator op;
78     struct expression * const *args;
79{
80  int i;
81  struct expression *newp;
82
83  /* If any of the argument could not be malloc'ed, just return NULL.  */
84  for (i = nargs - 1; i >= 0; i--)
85    if (args[i] == NULL)
86      goto fail;
87
88  /* Allocate a new expression.  */
89  newp = (struct expression *) malloc (sizeof (*newp));
90  if (newp != NULL)
91    {
92      newp->nargs = nargs;
93      newp->operation = op;
94      for (i = nargs - 1; i >= 0; i--)
95	newp->val.args[i] = args[i];
96      return newp;
97    }
98
99 fail:
100  for (i = nargs - 1; i >= 0; i--)
101    FREE_EXPRESSION (args[i]);
102
103  return NULL;
104}
105
106static inline struct expression *
107new_exp_0 (op)
108     enum operator op;
109{
110  return new_exp (0, op, NULL);
111}
112
113static inline struct expression *
114new_exp_1 (op, right)
115     enum operator op;
116     struct expression *right;
117{
118  struct expression *args[1];
119
120  args[0] = right;
121  return new_exp (1, op, args);
122}
123
124static struct expression *
125new_exp_2 (op, left, right)
126     enum operator op;
127     struct expression *left;
128     struct expression *right;
129{
130  struct expression *args[2];
131
132  args[0] = left;
133  args[1] = right;
134  return new_exp (2, op, args);
135}
136
137static inline struct expression *
138new_exp_3 (op, bexp, tbranch, fbranch)
139     enum operator op;
140     struct expression *bexp;
141     struct expression *tbranch;
142     struct expression *fbranch;
143{
144  struct expression *args[3];
145
146  args[0] = bexp;
147  args[1] = tbranch;
148  args[2] = fbranch;
149  return new_exp (3, op, args);
150}
151
152%}
153
154/* This declares that all operators have the same associativity and the
155   precedence order as in C.  See [Harbison, Steele: C, A Reference Manual].
156   There is no unary minus and no bitwise operators.
157   Operators with the same syntactic behaviour have been merged into a single
158   token, to save space in the array generated by bison.  */
159%right '?'		/*   ?		*/
160%left '|'		/*   ||		*/
161%left '&'		/*   &&		*/
162%left EQUOP2		/*   == !=	*/
163%left CMPOP2		/*   < > <= >=	*/
164%left ADDOP2		/*   + -	*/
165%left MULOP2		/*   * / %	*/
166%right '!'		/*   !		*/
167
168%token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2
169%token <num> NUMBER
170%type <exp> exp
171
172%%
173
174start:	  exp
175	  {
176	    if ($1 == NULL)
177	      YYABORT;
178	    ((struct parse_args *) arg)->res = $1;
179	  }
180	;
181
182exp:	  exp '?' exp ':' exp
183	  {
184	    $$ = new_exp_3 (qmop, $1, $3, $5);
185	  }
186	| exp '|' exp
187	  {
188	    $$ = new_exp_2 (lor, $1, $3);
189	  }
190	| exp '&' exp
191	  {
192	    $$ = new_exp_2 (land, $1, $3);
193	  }
194	| exp EQUOP2 exp
195	  {
196	    $$ = new_exp_2 ($2, $1, $3);
197	  }
198	| exp CMPOP2 exp
199	  {
200	    $$ = new_exp_2 ($2, $1, $3);
201	  }
202	| exp ADDOP2 exp
203	  {
204	    $$ = new_exp_2 ($2, $1, $3);
205	  }
206	| exp MULOP2 exp
207	  {
208	    $$ = new_exp_2 ($2, $1, $3);
209	  }
210	| '!' exp
211	  {
212	    $$ = new_exp_1 (lnot, $2);
213	  }
214	| 'n'
215	  {
216	    $$ = new_exp_0 (var);
217	  }
218	| NUMBER
219	  {
220	    if (($$ = new_exp_0 (num)) != NULL)
221	      $$->val.num = $1;
222	  }
223	| '(' exp ')'
224	  {
225	    $$ = $2;
226	  }
227	;
228
229%%
230
231void
232internal_function
233FREE_EXPRESSION (exp)
234     struct expression *exp;
235{
236  if (exp == NULL)
237    return;
238
239  /* Handle the recursive case.  */
240  switch (exp->nargs)
241    {
242    case 3:
243      FREE_EXPRESSION (exp->val.args[2]);
244      /* FALLTHROUGH */
245    case 2:
246      FREE_EXPRESSION (exp->val.args[1]);
247      /* FALLTHROUGH */
248    case 1:
249      FREE_EXPRESSION (exp->val.args[0]);
250      /* FALLTHROUGH */
251    default:
252      break;
253    }
254
255  free (exp);
256}
257
258
259static int
260yylex (lval, pexp)
261     YYSTYPE *lval;
262     const char **pexp;
263{
264  const char *exp = *pexp;
265  int result;
266
267  while (1)
268    {
269      if (exp[0] == '\0')
270	{
271	  *pexp = exp;
272	  return YYEOF;
273	}
274
275      if (exp[0] != ' ' && exp[0] != '\t')
276	break;
277
278      ++exp;
279    }
280
281  result = *exp++;
282  switch (result)
283    {
284    case '0': case '1': case '2': case '3': case '4':
285    case '5': case '6': case '7': case '8': case '9':
286      {
287	unsigned long int n = result - '0';
288	while (exp[0] >= '0' && exp[0] <= '9')
289	  {
290	    n *= 10;
291	    n += exp[0] - '0';
292	    ++exp;
293	  }
294	lval->num = n;
295	result = NUMBER;
296      }
297      break;
298
299    case '=':
300      if (exp[0] == '=')
301	{
302	  ++exp;
303	  lval->op = equal;
304	  result = EQUOP2;
305	}
306      else
307	result = YYERRCODE;
308      break;
309
310    case '!':
311      if (exp[0] == '=')
312	{
313	  ++exp;
314	  lval->op = not_equal;
315	  result = EQUOP2;
316	}
317      break;
318
319    case '&':
320    case '|':
321      if (exp[0] == result)
322	++exp;
323      else
324	result = YYERRCODE;
325      break;
326
327    case '<':
328      if (exp[0] == '=')
329	{
330	  ++exp;
331	  lval->op = less_or_equal;
332	}
333      else
334	lval->op = less_than;
335      result = CMPOP2;
336      break;
337
338    case '>':
339      if (exp[0] == '=')
340	{
341	  ++exp;
342	  lval->op = greater_or_equal;
343	}
344      else
345	lval->op = greater_than;
346      result = CMPOP2;
347      break;
348
349    case '*':
350      lval->op = mult;
351      result = MULOP2;
352      break;
353
354    case '/':
355      lval->op = divide;
356      result = MULOP2;
357      break;
358
359    case '%':
360      lval->op = module;
361      result = MULOP2;
362      break;
363
364    case '+':
365      lval->op = plus;
366      result = ADDOP2;
367      break;
368
369    case '-':
370      lval->op = minus;
371      result = ADDOP2;
372      break;
373
374    case 'n':
375    case '?':
376    case ':':
377    case '(':
378    case ')':
379      /* Nothing, just return the character.  */
380      break;
381
382    case ';':
383    case '\n':
384    case '\0':
385      /* Be safe and let the user call this function again.  */
386      --exp;
387      result = YYEOF;
388      break;
389
390    default:
391      result = YYERRCODE;
392#if YYDEBUG != 0
393      --exp;
394#endif
395      break;
396    }
397
398  *pexp = exp;
399
400  return result;
401}
402
403
404static void
405yyerror (str)
406     const char *str;
407{
408  /* Do nothing.  We don't print error messages here.  */
409}
410