source: trunk/third/texinfo/intl/plural.y @ 17660

Revision 17660, 8.0 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17659, which included commits to RCS files with non-trunk default branches.
Line 
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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}
Note: See TracBrowser for help on using the repository browser.