Blame intl/plural.y

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