
bison 3 apparently made a backwards incompatible change, dropped YYLEX_PARAM/YYPARSE_PARAM support and instead needs %param or %lex-param and %parse-param. Furthermore, there is no easy way to conditionalize on bison version in the *.y files. While e.g. glibc bumped bison requirement and just has the bison 3 compatible version, Richi said there are still systems with older bison where we want to build gcc. So, this patch instead determines during configure bison version, and depending on that when building plural.c (if building it at all) tweaks what is passed over to bison if needed. Tested with both bison 3 and bison 1.35, in each case with reconfiguring intl and building with make all-yes (as in my setup intl isn't normally used). 2020-04-16 Jakub Jelinek <jakub@redhat.com> PR bootstrap/92008 * configure.ac: Add check for bison >= 3, AC_DEFINE HAVE_BISON3 and AC_SUBST BISON3_YES and BISON3_NO. * Makefile.in (.y.c): Prefix $(YACC) invocation with @BISON3_NO@, add @BISON3_YES@ prefixed rule to adjust the *.y source using sed and adjust output afterwards. * plural-exp.h (PLURAL_PARSE): If HAVE_BISON3 is defined, use struct parse_args * type for arg instead of void *. * plural.y: Add magic /* BISON3 ... */ comments with bison >= 3 directives. (YYLEX_PARAM, YYPARSE_PARAM): Don't define if HAVE_BISON3 is defined. (yylex, yyerror): Adjust prototypes and definitions if HAVE_BISON3 is defined. * plural.c: Regenerated. * config.h.in: Regenerated. * configure: Regenerated.
434 lines
8.5 KiB
Text
434 lines
8.5 KiB
Text
%{
|
|
/* Expression parsing for plural form selection.
|
|
Copyright (C) 2000-2020 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
|
|
|
|
#ifndef HAVE_BISON3
|
|
#define YYLEX_PARAM &((struct parse_args *) arg)->cp
|
|
#define YYPARSE_PARAM arg
|
|
#endif
|
|
%}
|
|
%pure_parser
|
|
/* BISON3 %parse-param {struct parse_args *arg} */
|
|
/* BISON3 %lex-param {struct parse_args *arg} */
|
|
/* BISON3 %define api.pure full */
|
|
%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));
|
|
#ifdef HAVE_BISON3
|
|
static int yylex PARAMS ((YYSTYPE *lval, struct parse_args *arg));
|
|
static void yyerror PARAMS ((struct parse_args *arg, const char *str));
|
|
#else
|
|
static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
|
|
static void yyerror PARAMS ((const char *str));
|
|
#endif
|
|
|
|
/* 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);
|
|
}
|
|
|
|
|
|
#ifdef HAVE_BISON3
|
|
static int
|
|
yylex (lval, arg)
|
|
YYSTYPE *lval;
|
|
struct parse_args *arg;
|
|
{
|
|
const char **pexp = &arg->cp;
|
|
#else
|
|
static int
|
|
yylex (lval, pexp)
|
|
YYSTYPE *lval;
|
|
const char **pexp;
|
|
{
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
|
|
#ifdef HAVE_BISON3
|
|
static void
|
|
yyerror (arg, str)
|
|
struct parse_args *arg;
|
|
#else
|
|
static void
|
|
yyerror (str)
|
|
#endif
|
|
const char *str;
|
|
{
|
|
/* Do nothing. We don't print error messages here. */
|
|
}
|