mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			410 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			410 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| %{
 | |
| /* Expression parsing for plural form selection.
 | |
|    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
 | |
|    Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify it
 | |
|    under the terms of the GNU Library General Public License as published
 | |
|    by the Free Software Foundation; either version 2, or (at your option)
 | |
|    any later version.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Library General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Library General Public
 | |
|    License along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
 | |
|    USA.  */
 | |
| 
 | |
| /* The bison generated parser uses alloca.  AIX 3 forces us to put this
 | |
|    declaration at the beginning of the file.  The declaration in bison's
 | |
|    skeleton file comes too late.  This must come before <config.h>
 | |
|    because <config.h> may include arbitrary system headers.  */
 | |
| #if defined _AIX && !defined __GNUC__
 | |
|  #pragma alloca
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
| # include <config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stddef.h>
 | |
| #include <stdlib.h>
 | |
| #include "plural-exp.h"
 | |
| 
 | |
| /* The main function generated by the parser is called __gettextparse,
 | |
|    but we want it to be called PLURAL_PARSE.  */
 | |
| #ifndef _LIBC
 | |
| # define __gettextparse PLURAL_PARSE
 | |
| #endif
 | |
| 
 | |
| #define YYLEX_PARAM	&((struct parse_args *) arg)->cp
 | |
| #define YYPARSE_PARAM	arg
 | |
| %}
 | |
| %pure_parser
 | |
| %expect 7
 | |
| 
 | |
| %union {
 | |
|   unsigned long int num;
 | |
|   enum operator op;
 | |
|   struct expression *exp;
 | |
| }
 | |
| 
 | |
| %{
 | |
| /* Prototypes for local functions.  */
 | |
| static struct expression *new_exp PARAMS ((int nargs, enum operator op,
 | |
| 					   struct expression * const *args));
 | |
| static inline struct expression *new_exp_0 PARAMS ((enum operator op));
 | |
| static inline struct expression *new_exp_1 PARAMS ((enum operator op,
 | |
| 						   struct expression *right));
 | |
| static struct expression *new_exp_2 PARAMS ((enum operator op,
 | |
| 					     struct expression *left,
 | |
| 					     struct expression *right));
 | |
| static inline struct expression *new_exp_3 PARAMS ((enum operator op,
 | |
| 						   struct expression *bexp,
 | |
| 						   struct expression *tbranch,
 | |
| 						   struct expression *fbranch));
 | |
| static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
 | |
| static void yyerror PARAMS ((const char *str));
 | |
| 
 | |
| /* Allocation of expressions.  */
 | |
| 
 | |
| static struct expression *
 | |
| new_exp (nargs, op, args)
 | |
|      int nargs;
 | |
|      enum operator op;
 | |
|      struct expression * const *args;
 | |
| {
 | |
|   int i;
 | |
|   struct expression *newp;
 | |
| 
 | |
|   /* If any of the argument could not be malloc'ed, just return NULL.  */
 | |
|   for (i = nargs - 1; i >= 0; i--)
 | |
|     if (args[i] == NULL)
 | |
|       goto fail;
 | |
| 
 | |
|   /* Allocate a new expression.  */
 | |
|   newp = (struct expression *) malloc (sizeof (*newp));
 | |
|   if (newp != NULL)
 | |
|     {
 | |
|       newp->nargs = nargs;
 | |
|       newp->operation = op;
 | |
|       for (i = nargs - 1; i >= 0; i--)
 | |
| 	newp->val.args[i] = args[i];
 | |
|       return newp;
 | |
|     }
 | |
| 
 | |
|  fail:
 | |
|   for (i = nargs - 1; i >= 0; i--)
 | |
|     FREE_EXPRESSION (args[i]);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static inline struct expression *
 | |
| new_exp_0 (op)
 | |
|      enum operator op;
 | |
| {
 | |
|   return new_exp (0, op, NULL);
 | |
| }
 | |
| 
 | |
| static inline struct expression *
 | |
| new_exp_1 (op, right)
 | |
|      enum operator op;
 | |
|      struct expression *right;
 | |
| {
 | |
|   struct expression *args[1];
 | |
| 
 | |
|   args[0] = right;
 | |
|   return new_exp (1, op, args);
 | |
| }
 | |
| 
 | |
| static struct expression *
 | |
| new_exp_2 (op, left, right)
 | |
|      enum operator op;
 | |
|      struct expression *left;
 | |
|      struct expression *right;
 | |
| {
 | |
|   struct expression *args[2];
 | |
| 
 | |
|   args[0] = left;
 | |
|   args[1] = right;
 | |
|   return new_exp (2, op, args);
 | |
| }
 | |
| 
 | |
| static inline struct expression *
 | |
| new_exp_3 (op, bexp, tbranch, fbranch)
 | |
|      enum operator op;
 | |
|      struct expression *bexp;
 | |
|      struct expression *tbranch;
 | |
|      struct expression *fbranch;
 | |
| {
 | |
|   struct expression *args[3];
 | |
| 
 | |
|   args[0] = bexp;
 | |
|   args[1] = tbranch;
 | |
|   args[2] = fbranch;
 | |
|   return new_exp (3, op, args);
 | |
| }
 | |
| 
 | |
| %}
 | |
| 
 | |
| /* This declares that all operators have the same associativity and the
 | |
|    precedence order as in C.  See [Harbison, Steele: C, A Reference Manual].
 | |
|    There is no unary minus and no bitwise operators.
 | |
|    Operators with the same syntactic behaviour have been merged into a single
 | |
|    token, to save space in the array generated by bison.  */
 | |
| %right '?'		/*   ?		*/
 | |
| %left '|'		/*   ||		*/
 | |
| %left '&'		/*   &&		*/
 | |
| %left EQUOP2		/*   == !=	*/
 | |
| %left CMPOP2		/*   < > <= >=	*/
 | |
| %left ADDOP2		/*   + -	*/
 | |
| %left MULOP2		/*   * / %	*/
 | |
| %right '!'		/*   !		*/
 | |
| 
 | |
| %token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2
 | |
| %token <num> NUMBER
 | |
| %type <exp> exp
 | |
| 
 | |
| %%
 | |
| 
 | |
| start:	  exp
 | |
| 	  {
 | |
| 	    if ($1 == NULL)
 | |
| 	      YYABORT;
 | |
| 	    ((struct parse_args *) arg)->res = $1;
 | |
| 	  }
 | |
| 	;
 | |
| 
 | |
| exp:	  exp '?' exp ':' exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_3 (qmop, $1, $3, $5);
 | |
| 	  }
 | |
| 	| exp '|' exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 (lor, $1, $3);
 | |
| 	  }
 | |
| 	| exp '&' exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 (land, $1, $3);
 | |
| 	  }
 | |
| 	| exp EQUOP2 exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 ($2, $1, $3);
 | |
| 	  }
 | |
| 	| exp CMPOP2 exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 ($2, $1, $3);
 | |
| 	  }
 | |
| 	| exp ADDOP2 exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 ($2, $1, $3);
 | |
| 	  }
 | |
| 	| exp MULOP2 exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_2 ($2, $1, $3);
 | |
| 	  }
 | |
| 	| '!' exp
 | |
| 	  {
 | |
| 	    $$ = new_exp_1 (lnot, $2);
 | |
| 	  }
 | |
| 	| 'n'
 | |
| 	  {
 | |
| 	    $$ = new_exp_0 (var);
 | |
| 	  }
 | |
| 	| NUMBER
 | |
| 	  {
 | |
| 	    if (($$ = new_exp_0 (num)) != NULL)
 | |
| 	      $$->val.num = $1;
 | |
| 	  }
 | |
| 	| '(' exp ')'
 | |
| 	  {
 | |
| 	    $$ = $2;
 | |
| 	  }
 | |
| 	;
 | |
| 
 | |
| %%
 | |
| 
 | |
| void
 | |
| internal_function
 | |
| FREE_EXPRESSION (exp)
 | |
|      struct expression *exp;
 | |
| {
 | |
|   if (exp == NULL)
 | |
|     return;
 | |
| 
 | |
|   /* Handle the recursive case.  */
 | |
|   switch (exp->nargs)
 | |
|     {
 | |
|     case 3:
 | |
|       FREE_EXPRESSION (exp->val.args[2]);
 | |
|       /* FALLTHROUGH */
 | |
|     case 2:
 | |
|       FREE_EXPRESSION (exp->val.args[1]);
 | |
|       /* FALLTHROUGH */
 | |
|     case 1:
 | |
|       FREE_EXPRESSION (exp->val.args[0]);
 | |
|       /* FALLTHROUGH */
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   free (exp);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int
 | |
| yylex (lval, pexp)
 | |
|      YYSTYPE *lval;
 | |
|      const char **pexp;
 | |
| {
 | |
|   const char *exp = *pexp;
 | |
|   int result;
 | |
| 
 | |
|   while (1)
 | |
|     {
 | |
|       if (exp[0] == '\0')
 | |
| 	{
 | |
| 	  *pexp = exp;
 | |
| 	  return YYEOF;
 | |
| 	}
 | |
| 
 | |
|       if (exp[0] != ' ' && exp[0] != '\t')
 | |
| 	break;
 | |
| 
 | |
|       ++exp;
 | |
|     }
 | |
| 
 | |
|   result = *exp++;
 | |
|   switch (result)
 | |
|     {
 | |
|     case '0': case '1': case '2': case '3': case '4':
 | |
|     case '5': case '6': case '7': case '8': case '9':
 | |
|       {
 | |
| 	unsigned long int n = result - '0';
 | |
| 	while (exp[0] >= '0' && exp[0] <= '9')
 | |
| 	  {
 | |
| 	    n *= 10;
 | |
| 	    n += exp[0] - '0';
 | |
| 	    ++exp;
 | |
| 	  }
 | |
| 	lval->num = n;
 | |
| 	result = NUMBER;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case '=':
 | |
|       if (exp[0] == '=')
 | |
| 	{
 | |
| 	  ++exp;
 | |
| 	  lval->op = equal;
 | |
| 	  result = EQUOP2;
 | |
| 	}
 | |
|       else
 | |
| 	result = YYERRCODE;
 | |
|       break;
 | |
| 
 | |
|     case '!':
 | |
|       if (exp[0] == '=')
 | |
| 	{
 | |
| 	  ++exp;
 | |
| 	  lval->op = not_equal;
 | |
| 	  result = EQUOP2;
 | |
| 	}
 | |
|       break;
 | |
| 
 | |
|     case '&':
 | |
|     case '|':
 | |
|       if (exp[0] == result)
 | |
| 	++exp;
 | |
|       else
 | |
| 	result = YYERRCODE;
 | |
|       break;
 | |
| 
 | |
|     case '<':
 | |
|       if (exp[0] == '=')
 | |
| 	{
 | |
| 	  ++exp;
 | |
| 	  lval->op = less_or_equal;
 | |
| 	}
 | |
|       else
 | |
| 	lval->op = less_than;
 | |
|       result = CMPOP2;
 | |
|       break;
 | |
| 
 | |
|     case '>':
 | |
|       if (exp[0] == '=')
 | |
| 	{
 | |
| 	  ++exp;
 | |
| 	  lval->op = greater_or_equal;
 | |
| 	}
 | |
|       else
 | |
| 	lval->op = greater_than;
 | |
|       result = CMPOP2;
 | |
|       break;
 | |
| 
 | |
|     case '*':
 | |
|       lval->op = mult;
 | |
|       result = MULOP2;
 | |
|       break;
 | |
| 
 | |
|     case '/':
 | |
|       lval->op = divide;
 | |
|       result = MULOP2;
 | |
|       break;
 | |
| 
 | |
|     case '%':
 | |
|       lval->op = module;
 | |
|       result = MULOP2;
 | |
|       break;
 | |
| 
 | |
|     case '+':
 | |
|       lval->op = plus;
 | |
|       result = ADDOP2;
 | |
|       break;
 | |
| 
 | |
|     case '-':
 | |
|       lval->op = minus;
 | |
|       result = ADDOP2;
 | |
|       break;
 | |
| 
 | |
|     case 'n':
 | |
|     case '?':
 | |
|     case ':':
 | |
|     case '(':
 | |
|     case ')':
 | |
|       /* Nothing, just return the character.  */
 | |
|       break;
 | |
| 
 | |
|     case ';':
 | |
|     case '\n':
 | |
|     case '\0':
 | |
|       /* Be safe and let the user call this function again.  */
 | |
|       --exp;
 | |
|       result = YYEOF;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       result = YYERRCODE;
 | |
| #if YYDEBUG != 0
 | |
|       --exp;
 | |
| #endif
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   *pexp = exp;
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| yyerror (str)
 | |
|      const char *str;
 | |
| {
 | |
|   /* Do nothing.  We don't print error messages here.  */
 | |
| }
 |