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