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