1 29 30 package com.caucho.quercus.lib.gettext.expr; 31 32 35 class PluralExprParser 36 { 37 final static int INTEGER = 256; 38 39 final static int EQ = 270; 40 final static int NEQ = 271; 41 final static int LE = 272; 42 final static int GE = 273; 43 44 final static int AND = 280; 45 final static int OR = 281; 46 47 final static int VARIABLE_N = 290; 48 final static int UNKNOWN = 291; 49 final static int UNSET = 292; 50 51 private CharSequence _expr; 52 private int _exprLength; 53 private int _parseIndex; 54 55 private Expr _npluralsExpr; 56 private Expr _pluralExpr; 57 58 private int _peekToken; 59 private int _integer; 60 61 private boolean _isError; 62 private boolean _isInitialized; 63 64 protected PluralExprParser(CharSequence expr) 65 { 66 _expr = expr; 67 _exprLength = expr.length(); 68 69 _isInitialized = false; 70 } 71 72 public Expr getNpluralsExpr() 73 { 74 if (! _isInitialized) 75 init(); 76 77 if (_isError) 78 return null; 79 80 return _npluralsExpr; 81 } 82 83 public Expr getPluralExpr() 84 { 85 if (! _isInitialized) 86 init(); 87 88 if (_isError) 89 return null; 90 91 return _pluralExpr; 92 } 93 94 private void init() 95 { 96 _parseIndex = 0; 97 _peekToken = UNSET; 98 _isError = false; 99 100 parseAssignExpr(); 101 parseAssignExpr(); 102 103 _isInitialized = true; 104 } 105 106 private void parseAssignExpr() 107 { 108 int ch = consumeWhiteSpace(); 109 110 boolean isNplurals; 111 112 if (ch == 'n' && 113 read() == 'p' && 114 read() == 'l' && 115 read() == 'u' && 116 read() == 'r' && 117 read() == 'a' && 118 read() == 'l' && 119 read() == 's') { 120 isNplurals = true; 121 } 122 else if (ch == 'p' && 123 read() == 'l' && 124 read() == 'u' && 125 read() == 'r' && 126 read() == 'a' && 127 read() == 'l') { 128 isNplurals = false; 129 } 130 else 131 return; 132 133 ch = consumeWhiteSpace(); 134 135 if (ch != '=') 136 return; 137 138 if (isNplurals) 139 _npluralsExpr = parseIfExpr(); 140 else 141 _pluralExpr = parseIfExpr(); 142 143 parseToken(); 145 } 146 147 private Expr parseLiteralExpr() 148 { 149 int token = parseToken(); 150 151 if (token == INTEGER) 152 return new LiteralExpr(_integer); 153 else if (token == VARIABLE_N) 154 return NExpr.N_EXPR; 155 else 156 return error("Expected INTEGER"); 157 } 158 159 private Expr parseParenExpr() 160 { 161 int token = parseToken(); 162 163 if (token != '(') { 164 _peekToken = token; 165 return parseLiteralExpr(); 166 } 167 168 Expr expr = parseIfExpr(); 169 if (parseToken() != ')') 170 return error("Expected ')'"); 171 172 return expr; 173 } 174 175 private Expr parseMulExpr() 176 { 177 Expr expr = parseParenExpr(); 178 179 while (true) { 180 int token = parseToken(); 181 switch (token) { 182 case '%': 183 expr = new ModExpr(expr, parseParenExpr()); 184 break; 185 case '*': 186 expr = new MulExpr(expr, parseParenExpr()); 187 break; 188 case '/': 189 expr = new DivExpr(expr, parseParenExpr()); 190 break; 191 default: 192 _peekToken = token; 193 return expr; 194 } 195 } 196 } 197 198 private Expr parseAddExpr() 199 { 200 Expr expr = parseMulExpr(); 201 202 while (true) { 203 int token = parseToken(); 204 205 switch (token) { 206 case '+': 207 expr = new AddExpr(expr, parseMulExpr()); 208 break; 209 case '-': 210 expr = new SubExpr(expr, parseMulExpr()); 211 break; 212 default: 213 _peekToken = token; 214 return expr; 215 } 216 } 217 } 218 219 private Expr parseCmpExpr() 220 { 221 Expr expr = parseAddExpr(); 222 223 while (true) { 224 int token = parseToken(); 225 switch (token) { 226 case '>': 227 expr = new GTExpr(expr, parseAddExpr()); 228 break; 229 case '<': 230 expr = new LTExpr(expr, parseAddExpr()); 231 break; 232 case GE: 233 expr = new GEExpr(expr, parseAddExpr()); 234 break; 235 case LE: 236 expr = new LEExpr(expr, parseAddExpr()); 237 break; 238 case EQ: 239 expr = new EQExpr(expr, parseAddExpr()); 240 break; 241 case NEQ: 242 expr = new NEQExpr(expr, parseAddExpr()); 243 break; 244 default: 245 _peekToken = token; 246 return expr; 247 } 248 } 249 } 250 251 private Expr parseAndExpr() 252 { 253 Expr expr = parseCmpExpr(); 254 255 while (true) { 256 int token = parseToken(); 257 if (token != AND) { 258 _peekToken = token; 259 return expr; 260 } 261 262 expr = new AndExpr(expr, parseCmpExpr()); 263 } 264 } 265 266 private Expr parseOrExpr() 267 { 268 Expr expr = parseAndExpr(); 269 270 while (true) { 271 int token = parseToken(); 272 if (token != OR) { 273 _peekToken = token; 274 return expr; 275 } 276 277 expr = new OrExpr(expr, parseAndExpr()); 278 } 279 } 280 281 private Expr parseIfExpr() 282 { 283 Expr expr = parseOrExpr(); 284 285 int token = parseToken(); 286 if (token != '?') { 287 _peekToken = token; 288 return expr; 289 } 290 291 Expr trueExpr = parseIfExpr(); 292 293 token = parseToken(); 294 if (token != ':') 295 return error("Expected ':'"); 296 297 Expr falseExpr = parseIfExpr(); 298 299 return new IfExpr(expr, trueExpr, falseExpr); 300 } 301 302 private int parseToken() 303 { 304 305 if (_peekToken != UNSET) { 306 int toReturn = _peekToken; 307 _peekToken = UNSET; 308 return toReturn; 309 } 310 311 int ch = consumeWhiteSpace(); 312 313 switch (ch) { 314 case '(': 315 case ')': 316 case '?': 317 case ':': 318 case ';': 319 case '+': 320 case '-': 321 case '%': 322 case '*': 323 case '/': 324 return ch; 325 case '>': 326 if (read() == '=') 327 return GE; 328 unread(); 329 return '>'; 330 case '<': 331 if (read() == '=') 332 return LE; 333 unread(); 334 return '<'; 335 case '=': 336 if (read() == '=') 337 return EQ; 338 return UNKNOWN; 339 case '!': 340 if (read() == '=') 341 return NEQ; 342 return UNKNOWN; 343 case '&': 344 if (read() == '&') 345 return AND; 346 return UNKNOWN; 347 case '|': 348 if (read() == '|') 349 return OR; 350 return UNKNOWN; 351 } 352 353 return parseIntegerToken(ch); 354 } 355 356 private int parseIntegerToken(int ch) 357 { 358 if ('0' <= ch && ch <= '9') { 359 _integer = ch - '0'; 360 for (ch = read(); '0' <= ch && ch <= '9'; ch = read()) { 361 _integer = _integer * 10 + ch - '0'; 362 } 363 364 unread(); 365 return INTEGER; 366 } 367 368 else if (ch == 'n') { 369 if (Character.isLetter(read())) 370 return UNKNOWN; 371 372 unread(); 373 return VARIABLE_N; 374 } 375 376 return UNKNOWN; 377 } 378 379 382 private int consumeWhiteSpace() 383 { 384 while (true) { 385 int ch = read(); 386 switch (ch) { 387 case ' ': 388 case '\n': 389 case '\t': 390 case '\r': 391 continue; 392 default: 393 return ch; 394 } 395 } 396 } 397 398 private int read() 399 { 400 if (_parseIndex < _exprLength) 401 return _expr.charAt(_parseIndex++); 402 else 403 return -1; 404 } 405 406 private void unread() 407 { 408 if (_parseIndex > 0 && _parseIndex < _exprLength) 409 _parseIndex--; 410 } 411 412 private Expr error(String message) 413 { 414 _isError = true; 415 return NExpr.N_EXPR; 416 } 417 } 418 | Popular Tags |