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