411 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			411 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
%{
 | 
						|
/* plural.y - Expression parsing for plural form selection. */
 | 
						|
 | 
						|
/* Copyright (C) 2000, 2001, 2005-2009 Free Software Foundation, Inc.
 | 
						|
   Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
 | 
						|
 | 
						|
   This file is part of GNU Bash.
 | 
						|
 | 
						|
   Bash is free software: you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation, either version 3 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
 | 
						|
   Bash 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 General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
*/
 | 
						|
 | 
						|
/* 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.  */
 | 
						|
}
 |