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