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