1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-02 08:57:19 -04:00
elinks/src/intl/gettext/plural.y
Witold Filipczyk 0fea79cc8f [cflags] Removed -Wno-pointer-sign
Likely some new bugs were introduced by this change.
The long term goal is clean compilation by g++.
2021-01-02 16:20:27 +01:00

386 lines
7.6 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 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <stdlib.h>
#include "intl/gettext/gettextP.h"
%}
%parse-param {struct parse_args *arg}
%lex-param {struct parse_args *arg}
%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(int nargs, enum operator_ op,
struct expression * const *args);
static inline struct expression *new_exp_0(enum operator_ op);
static inline struct expression *new_exp_1(enum operator_ op,
struct expression *right);
static struct expression *new_exp_2(enum operator_ op,
struct expression *left,
struct expression *right);
static inline struct expression *new_exp_3(enum operator_ op,
struct expression *bexp,
struct expression *tbranch,
struct expression *fbranch);
static int yylex(YYSTYPE *lval, struct parse_args *arg);
static void yyerror(struct parse_args *arg, const char *str);
/* Allocation of expressions. */
static struct expression *
new_exp(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--)
gettext_free_exp__ (args[i]);
return NULL;
}
static inline struct expression *
new_exp_0(enum operator_ op)
{
return new_exp (0, op, NULL);
}
static inline struct expression *
new_exp_1(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(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(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
gettext_free_exp__(struct expression *exp)
{
if (exp == NULL)
return;
/* Handle the recursive case. */
switch (exp->nargs)
{
case 3:
gettext_free_exp__ (exp->val.args[2]);
/* FALLTHROUGH */
case 2:
gettext_free_exp__ (exp->val.args[1]);
/* FALLTHROUGH */
case 1:
gettext_free_exp__ (exp->val.args[0]);
/* FALLTHROUGH */
default:
break;
}
free (exp);
}
static int
yylex(YYSTYPE *lval, struct parse_args *arg)
{
const char *exp = arg->cp;
int result;
while (1)
{
if (exp[0] == '\0')
{
arg->cp = 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;
}
arg->cp = exp;
return result;
}
static void
yyerror(struct parse_args *arg, const char *str)
{
/* Do nothing. We don't print error messages here. */
}