1 %{ 2 /* Expression parsing for plural form selection. 3 Copyright (C) 2000, 2001 Free Software Foundation, Inc. 4 Written by Ulrich Drepper <drepper (at) cygnus.com>, 2000. 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Library General Public License as published 8 by the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public 17 License along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 19 USA. */ 20 21 /* The bison generated parser uses alloca. AIX 3 forces us to put this 22 declaration at the beginning of the file. The declaration in bison's 23 skeleton file comes too late. This must come before <config.h> 24 because <config.h> may include arbitrary system headers. */ 25 #if defined _AIX && !defined __GNUC__ 26 #pragma alloca 27 #endif 28 29 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif 32 33 #include <stddef.h> 34 #include <stdlib.h> 35 #include "plural-exp.h" 36 37 /* The main function generated by the parser is called __gettextparse, 38 but we want it to be called PLURAL_PARSE. */ 39 #ifndef _LIBC 40 # define __gettextparse PLURAL_PARSE 41 #endif 42 43 #define YYLEX_PARAM &((struct parse_args *) arg)->cp 44 #define YYPARSE_PARAM arg 45 %} 46 %pure_parser 47 %expect 7 48 49 %union { 50 unsigned long int num; 51 enum operator op; 52 struct expression *exp; 53 } 54 55 %{ 56 /* Prototypes for local functions. */ 57 static struct expression *new_exp PARAMS ((int nargs, enum operator op, 58 struct expression * const *args)); 59 static inline struct expression *new_exp_0 PARAMS ((enum operator op)); 60 static inline struct expression *new_exp_1 PARAMS ((enum operator op, 61 struct expression *right)); 62 static struct expression *new_exp_2 PARAMS ((enum operator op, 63 struct expression *left, 64 struct expression *right)); 65 static inline struct expression *new_exp_3 PARAMS ((enum operator op, 66 struct expression *bexp, 67 struct expression *tbranch, 68 struct expression *fbranch)); 69 static int yylex PARAMS ((YYSTYPE *lval, const char **pexp)); 70 static void yyerror PARAMS ((const char *str)); 71 72 /* Allocation of expressions. */ 73 74 static struct expression * 75 new_exp (nargs, op, args) 76 int nargs; 77 enum operator op; 78 struct expression * const *args; 79 { 80 int i; 81 struct expression *newp; 82 83 /* If any of the argument could not be malloc'ed, just return NULL. */ 84 for (i = nargs - 1; i >= 0; i--) 85 if (args[i] == NULL) 86 goto fail; 87 88 /* Allocate a new expression. */ 89 newp = (struct expression *) malloc (sizeof (*newp)); 90 if (newp != NULL) 91 { 92 newp->nargs = nargs; 93 newp->operation = op; 94 for (i = nargs - 1; i >= 0; i--) 95 newp->val.args[i] = args[i]; 96 return newp; 97 } 98 99 fail: 100 for (i = nargs - 1; i >= 0; i--) 101 FREE_EXPRESSION (args[i]); 102 103 return NULL; 104 } 105 106 static inline struct expression * 107 new_exp_0 (op) 108 enum operator op; 109 { 110 return new_exp (0, op, NULL); 111 } 112 113 static inline struct expression * 114 new_exp_1 (op, right) 115 enum operator op; 116 struct expression *right; 117 { 118 struct expression *args[1]; 119 120 args[0] = right; 121 return new_exp (1, op, args); 122 } 123 124 static struct expression * 125 new_exp_2 (op, left, right) 126 enum operator op; 127 struct expression *left; 128 struct expression *right; 129 { 130 struct expression *args[2]; 131 132 args[0] = left; 133 args[1] = right; 134 return new_exp (2, op, args); 135 } 136 137 static inline struct expression * 138 new_exp_3 (op, bexp, tbranch, fbranch) 139 enum operator op; 140 struct expression *bexp; 141 struct expression *tbranch; 142 struct expression *fbranch; 143 { 144 struct expression *args[3]; 145 146 args[0] = bexp; 147 args[1] = tbranch; 148 args[2] = fbranch; 149 return new_exp (3, op, args); 150 } 151 152 %} 153 154 /* This declares that all operators have the same associativity and the 155 precedence order as in C. See [Harbison, Steele: C, A Reference Manual]. 156 There is no unary minus and no bitwise operators. 157 Operators with the same syntactic behaviour have been merged into a single 158 token, to save space in the array generated by bison. */ 159 %right '?' /* ? */ 160 %left '|' /* || */ 161 %left '&' /* && */ 162 %left EQUOP2 /* == != */ 163 %left CMPOP2 /* < > <= >= */ 164 %left ADDOP2 /* + - */ 165 %left MULOP2 /* * / % */ 166 %right '!' /* ! */ 167 168 %token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2 169 %token <num> NUMBER 170 %type <exp> exp 171 172 %% 173 174 start: exp 175 { 176 if ($1 == NULL) 177 YYABORT; 178 ((struct parse_args *) arg)->res = $1; 179 } 180 ; 181 182 exp: exp '?' exp ':' exp 183 { 184 $$ = new_exp_3 (qmop, $1, $3, $5); 185 } 186 | exp '|' exp 187 { 188 $$ = new_exp_2 (lor, $1, $3); 189 } 190 | exp '&' exp 191 { 192 $$ = new_exp_2 (land, $1, $3); 193 } 194 | exp EQUOP2 exp 195 { 196 $$ = new_exp_2 ($2, $1, $3); 197 } 198 | exp CMPOP2 exp 199 { 200 $$ = new_exp_2 ($2, $1, $3); 201 } 202 | exp ADDOP2 exp 203 { 204 $$ = new_exp_2 ($2, $1, $3); 205 } 206 | exp MULOP2 exp 207 { 208 $$ = new_exp_2 ($2, $1, $3); 209 } 210 | '!' exp 211 { 212 $$ = new_exp_1 (lnot, $2); 213 } 214 | 'n' 215 { 216 $$ = new_exp_0 (var); 217 } 218 | NUMBER 219 { 220 if (($$ = new_exp_0 (num)) != NULL) 221 $$->val.num = $1; 222 } 223 | '(' exp ')' 224 { 225 $$ = $2; 226 } 227 ; 228 229 %% 230 231 void 232 internal_function 233 FREE_EXPRESSION (exp) 234 struct expression *exp; 235 { 236 if (exp == NULL) 237 return; 238 239 /* Handle the recursive case. */ 240 switch (exp->nargs) 241 { 242 case 3: 243 FREE_EXPRESSION (exp->val.args[2]); 244 /* FALLTHROUGH */ 245 case 2: 246 FREE_EXPRESSION (exp->val.args[1]); 247 /* FALLTHROUGH */ 248 case 1: 249 FREE_EXPRESSION (exp->val.args[0]); 250 /* FALLTHROUGH */ 251 default: 252 break; 253 } 254 255 free (exp); 256 } 257 258 259 static int 260 yylex (lval, pexp) 261 YYSTYPE *lval; 262 const char **pexp; 263 { 264 const char *exp = *pexp; 265 int result; 266 267 while (1) 268 { 269 if (exp[0] == '\0') 270 { 271 *pexp = exp; 272 return YYEOF; 273 } 274 275 if (exp[0] != ' ' && exp[0] != '\t') 276 break; 277 278 ++exp; 279 } 280 281 result = *exp++; 282 switch (result) 283 { 284 case '0': case '1': case '2': case '3': case '4': 285 case '5': case '6': case '7': case '8': case '9': 286 { 287 unsigned long int n = result - '0'; 288 while (exp[0] >= '0' && exp[0] <= '9') 289 { 290 n *= 10; 291 n += exp[0] - '0'; 292 ++exp; 293 } 294 lval->num = n; 295 result = NUMBER; 296 } 297 break; 298 299 case '=': 300 if (exp[0] == '=') 301 { 302 ++exp; 303 lval->op = equal; 304 result = EQUOP2; 305 } 306 else 307 result = YYERRCODE; 308 break; 309 310 case '!': 311 if (exp[0] == '=') 312 { 313 ++exp; 314 lval->op = not_equal; 315 result = EQUOP2; 316 } 317 break; 318 319 case '&': 320 case '|': 321 if (exp[0] == result) 322 ++exp; 323 else 324 result = YYERRCODE; 325 break; 326 327 case '<': 328 if (exp[0] == '=') 329 { 330 ++exp; 331 lval->op = less_or_equal; 332 } 333 else 334 lval->op = less_than; 335 result = CMPOP2; 336 break; 337 338 case '>': 339 if (exp[0] == '=') 340 { 341 ++exp; 342 lval->op = greater_or_equal; 343 } 344 else 345 lval->op = greater_than; 346 result = CMPOP2; 347 break; 348 349 case '*': 350 lval->op = mult; 351 result = MULOP2; 352 break; 353 354 case '/': 355 lval->op = divide; 356 result = MULOP2; 357 break; 358 359 case '%': 360 lval->op = module; 361 result = MULOP2; 362 break; 363 364 case '+': 365 lval->op = plus; 366 result = ADDOP2; 367 break; 368 369 case '-': 370 lval->op = minus; 371 result = ADDOP2; 372 break; 373 374 case 'n': 375 case '?': 376 case ':': 377 case '(': 378 case ')': 379 /* Nothing, just return the character. */ 380 break; 381 382 case ';': 383 case '\n': 384 case '\0': 385 /* Be safe and let the user call this function again. */ 386 --exp; 387 result = YYEOF; 388 break; 389 390 default: 391 result = YYERRCODE; 392 #if YYDEBUG != 0 393 --exp; 394 #endif 395 break; 396 } 397 398 *pexp = exp; 399 400 return result; 401 } 402 403 404 static void 405 yyerror (str) 406 const char *str; 407 { 408 /* Do nothing. We don't print error messages here. */ 409 } 410