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