001/* 002 * Units of Measurement Systems for Java 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 008 * 009 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 010 * 011 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 012 * 013 * 3. Neither the name of JSR-363, Units of Measurement nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission. 014 * 015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 017 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 019 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 020 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 021 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 022 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 023 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 024 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 025 */ 026package systems.uom.ucum.internal.format; 027 028import static tec.uom.se.AbstractUnit.ONE; 029 030import javax.measure.Unit; 031 032import tec.uom.se.AbstractUnit; 033import tec.uom.se.format.SymbolMap; 034import tec.uom.se.unit.MetricPrefix; 035import static systems.uom.ucum.internal.format.UCUMTokenConstants.*; 036 037/** 038 * <p> 039 * Parser definition for parsing {@link AbstractUnit Unit}s 040 * according to the <a href="http://unitsofmeasure.org"> 041 * Uniform Code for CommonUnits of Measure</a>. 042 * 043 * @author <a href="mailto:eric-r@northwestern.edu">Eric Russell</a> 044 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 045 * @see <a href="http://unitsofmeasure.org">UCUM</a> 046 * @version 0.6, March 14, 2017 047 */ 048public final class UCUMFormatParser { 049 050 private SymbolMap symbols; 051 052 public UCUMFormatParser(SymbolMap symbols, java.io.InputStream in) { 053 this(in); 054 this.symbols = symbols; 055 } 056 057// 058// Parser productions 059// 060 final public Unit parseUnit() throws TokenException { 061 Unit u; 062 u = Term(); 063 jj_consume_token(0); 064 { 065 return u; 066 } 067 } 068 069 final public Unit Term() throws TokenException { 070 Unit result = ONE; 071 Unit temp = ONE; 072 result = Component(); 073 label_1: 074 while (true) { 075 switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { 076 case DOT: 077 case SOLIDUS: 078 break; 079 default: 080 jj_la1[0] = jj_gen; 081 break label_1; 082 } 083 switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { 084 case DOT: 085 jj_consume_token(DOT); 086 temp = Component(); 087 result = result.multiply(temp); 088 break; 089 case SOLIDUS: 090 jj_consume_token(SOLIDUS); 091 temp = Component(); 092 result = result.divide(temp); 093 break; 094 default: 095 jj_la1[1] = jj_gen; 096 jj_consume_token(-1); 097 throw new TokenException(); 098 } 099 } 100 { 101 return result; 102 } 103 } 104 105 final public Unit Component() throws TokenException { 106 Unit result = (AbstractUnit) ONE; 107 Token token = null; 108 if (jj_2_1(2147483647)) { 109 result = Annotatable(); 110 token = jj_consume_token(ANNOTATION); 111 { 112 return ((AbstractUnit)result).annotate(token.image.substring(1, token.image.length() - 1)); 113 } 114 } else { 115 switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { 116 case ATOM: 117 result = Annotatable(); { 118 return result; 119 } 120 case ANNOTATION: 121 token = jj_consume_token(ANNOTATION); { 122 return ((AbstractUnit)result).annotate(token.image.substring(1, token.image.length() - 1)); 123 } 124 case FACTOR: 125 token = jj_consume_token(FACTOR); 126 long factor = Long.parseLong(token.image); { 127 return result.multiply(factor); 128 } 129 case SOLIDUS: 130 jj_consume_token(SOLIDUS); 131 result = Component(); { 132 return ONE.divide(result); 133 } 134 case 14: 135 jj_consume_token(14); 136 result = Term(); 137 jj_consume_token(15); { 138 return result; 139 } 140 default: 141 jj_la1[2] = jj_gen; 142 jj_consume_token(-1); 143 throw new TokenException(); 144 } 145 } 146 } 147 148 final public Unit Annotatable() throws TokenException { 149 Unit result = ONE; 150 Token token1 = null; 151 Token token2 = null; 152 if (jj_2_2(2147483647)) { 153 result = SimpleUnit(); 154 switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { 155 case SIGN: 156 token1 = jj_consume_token(SIGN); 157 break; 158 default: 159 jj_la1[3] = jj_gen; 160 } 161 token2 = jj_consume_token(FACTOR); 162 int exponent = Integer.parseInt(token2.image); 163 if ((token1 != null) && token1.image.equals("-")) { 164 { 165 return result.pow(-exponent); 166 } 167 } else { 168 { 169 return result.pow(exponent); 170 } 171 } 172 } else { 173 switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { 174 case ATOM: 175 result = SimpleUnit(); { 176 return result; 177 } 178 default: 179 jj_la1[4] = jj_gen; 180 jj_consume_token(-1); 181 throw new TokenException(); 182 } 183 } 184 } 185 186 final public Unit SimpleUnit() throws TokenException { 187 Token token = null; 188 token = jj_consume_token(ATOM); 189 Unit unit = symbols.getUnit(token.image); 190 if (unit == null) { 191 MetricPrefix prefix = symbols.getPrefix(token.image); 192 if (prefix != null) { 193 String prefixSymbol = symbols.getSymbol(prefix); 194 unit = symbols.getUnit(token.image.substring(prefixSymbol.length())); 195 if (unit != null) { 196 { 197 return unit.transform(prefix.getConverter()); 198 } 199 } 200 } 201 { 202 throw new TokenException(); 203 } 204 } else { 205 { 206 return unit; 207 } 208 } 209 } 210 211 private boolean jj_2_1(int xla) { 212 jj_la = xla; 213 jj_lastpos = jj_scanpos = token; 214 try { 215 return !jj_3_1(); 216 } catch (LookaheadSuccess ls) { 217 return true; 218 } finally { 219 jj_save(0, xla); 220 } 221 } 222 223 private boolean jj_2_2(int xla) { 224 jj_la = xla; 225 jj_lastpos = jj_scanpos = token; 226 try { 227 return !jj_3_2(); 228 } catch (LookaheadSuccess ls) { 229 return true; 230 } finally { 231 jj_save(1, xla); 232 } 233 } 234 235 private boolean jj_3_1() { 236 return jj_3R_2() || jj_scan_token(ANNOTATION); 237 } 238 239 private boolean jj_3R_5() { 240 return jj_3R_3(); 241 } 242 243 private boolean jj_3R_4() { 244 if (jj_3R_3()) 245 return true; 246 Token xsp; 247 xsp = jj_scanpos; 248 if (jj_scan_token(10)) 249 jj_scanpos = xsp; 250 return jj_scan_token(FACTOR); 251 } 252 253 private boolean jj_3_2() { 254 if (jj_3R_3()) 255 return true; 256 Token xsp; 257 xsp = jj_scanpos; 258 if (jj_scan_token(10)) 259 jj_scanpos = xsp; 260 return jj_scan_token(FACTOR); 261 } 262 263 private boolean jj_3R_3() { 264 return jj_scan_token(ATOM); 265 } 266 267 private boolean jj_3R_2() { 268 Token xsp; 269 xsp = jj_scanpos; 270 if (jj_3R_4()) { 271 jj_scanpos = xsp; 272 if (jj_3R_5()) 273 return true; 274 } 275 return false; 276 } 277 /** Generated Token Manager. */ 278 public UCUMTokenManager token_source; 279 280 UCUMCharStream jj_input_stream; 281 282 /** Current token. */ 283 public Token token; 284 285 /** Next token. */ 286 public Token jj_nt; 287 288 private int jj_ntk; 289 290 private Token jj_scanpos, jj_lastpos; 291 292 private int jj_la; 293 294 private int jj_gen; 295 296 final private int[] jj_la1 = new int[5]; 297 298 static private int[] jj_la1_0; 299 300 static { 301 jj_la1_init_0(); 302 } 303 304 private static void jj_la1_init_0() { 305 jj_la1_0 = new int[]{0x1800, 0x1800, 0x7300, 0x400, 0x2000,}; 306 } 307 final private JJCalls[] jj_2_rtns = new JJCalls[2]; 308 309 private boolean jj_rescan = false; 310 311 private int jj_gc = 0; 312 313 /** Constructor with InputStream. */ 314 public UCUMFormatParser(java.io.InputStream stream) { 315 this(stream, null); 316 } 317 318 /** Constructor with InputStream and supplied encoding */ 319 public UCUMFormatParser(java.io.InputStream stream, String encoding) { 320 try { 321 jj_input_stream = new UCUMCharStream(stream, encoding, 1, 1); 322 } catch (java.io.UnsupportedEncodingException e) { 323 throw new RuntimeException(e); 324 } 325 token_source = new UCUMTokenManager(jj_input_stream); 326 token = new Token(); 327 jj_ntk = -1; 328 jj_gen = 0; 329 for (int i = 0; i < 5; i++) { 330 jj_la1[i] = -1; 331 } 332 for (int i = 0; i < jj_2_rtns.length; i++) { 333 jj_2_rtns[i] = new JJCalls(); 334 } 335 } 336 337 /** Reinitialise. */ 338 public void ReInit(java.io.InputStream stream) { 339 ReInit(stream, null); 340 } 341 342 /** Reinitialise. */ 343 public void ReInit(java.io.InputStream stream, String encoding) { 344 try { 345 jj_input_stream.ReInit(stream, encoding, 1, 1); 346 } catch (java.io.UnsupportedEncodingException e) { 347 throw new RuntimeException(e); 348 } 349 token_source.ReInit(jj_input_stream); 350 token = new Token(); 351 jj_ntk = -1; 352 jj_gen = 0; 353 for (int i = 0; i < 5; i++) { 354 jj_la1[i] = -1; 355 } 356 for (int i = 0; i < jj_2_rtns.length; i++) { 357 jj_2_rtns[i] = new JJCalls(); 358 } 359 } 360 361 /** Constructor. */ 362 public UCUMFormatParser(java.io.Reader stream) { 363 jj_input_stream = new UCUMCharStream(stream, 1, 1); 364 token_source = new UCUMTokenManager(jj_input_stream); 365 token = new Token(); 366 jj_ntk = -1; 367 jj_gen = 0; 368 for (int i = 0; i < 5; i++) { 369 jj_la1[i] = -1; 370 } 371 for (int i = 0; i < jj_2_rtns.length; i++) { 372 jj_2_rtns[i] = new JJCalls(); 373 } 374 } 375 376 /** Reinitialise. */ 377 public void ReInit(java.io.Reader stream) { 378 jj_input_stream.ReInit(stream, 1, 1); 379 token_source.ReInit(jj_input_stream); 380 token = new Token(); 381 jj_ntk = -1; 382 jj_gen = 0; 383 for (int i = 0; i < 5; i++) { 384 jj_la1[i] = -1; 385 } 386 for (int i = 0; i < jj_2_rtns.length; i++) { 387 jj_2_rtns[i] = new JJCalls(); 388 } 389 } 390 391 /** Constructor with generated Token Manager. */ 392 public UCUMFormatParser(UCUMTokenManager tm) { 393 token_source = tm; 394 token = new Token(); 395 jj_ntk = -1; 396 jj_gen = 0; 397 for (int i = 0; i < 5; i++) { 398 jj_la1[i] = -1; 399 } 400 for (int i = 0; i < jj_2_rtns.length; i++) { 401 jj_2_rtns[i] = new JJCalls(); 402 } 403 } 404 405 /** Reinitialise. */ 406 public void ReInit(UCUMTokenManager tm) { 407 token_source = tm; 408 token = new Token(); 409 jj_ntk = -1; 410 jj_gen = 0; 411 for (int i = 0; i < 5; i++) { 412 jj_la1[i] = -1; 413 } 414 for (int i = 0; i < jj_2_rtns.length; i++) { 415 jj_2_rtns[i] = new JJCalls(); 416 } 417 } 418 419 private Token jj_consume_token(int kind) throws TokenException { 420 Token oldToken; 421 if ((oldToken = token).next != null) 422 token = token.next; 423 else 424 token = token.next = token_source.getNextToken(); 425 jj_ntk = -1; 426 if (token.kind == kind) { 427 jj_gen++; 428 if (++jj_gc > 100) { 429 jj_gc = 0; 430 for (JJCalls jj_2_rtn : jj_2_rtns) { 431 JJCalls c = jj_2_rtn; 432 while (c != null) { 433 if (c.gen < jj_gen) 434 c.first = null; 435 c = c.next; 436 } 437 } 438 } 439 return token; 440 } 441 token = oldToken; 442 jj_kind = kind; 443 throw raiseTokenException(); 444 } 445 446 static private final class LookaheadSuccess extends java.lang.Error { 447 448 /** 449 * 450 */ 451 private static final long serialVersionUID = -1747326813448392305L; 452 453 } 454 final private LookaheadSuccess jj_ls = new LookaheadSuccess(); 455 456 private boolean jj_scan_token(int kind) { 457 if (jj_scanpos == jj_lastpos) { 458 jj_la--; 459 if (jj_scanpos.next == null) { 460 jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); 461 } else { 462 jj_lastpos = jj_scanpos = jj_scanpos.next; 463 } 464 } else { 465 jj_scanpos = jj_scanpos.next; 466 } 467 if (jj_rescan) { 468 int i = 0; 469 Token tok = token; 470 while (tok != null && tok != jj_scanpos) { 471 i++; 472 tok = tok.next; 473 } 474 if (tok != null) 475 jj_add_error_token(kind, i); 476 } 477 if (jj_scanpos.kind != kind) 478 return true; 479 if (jj_la == 0 && jj_scanpos == jj_lastpos) 480 throw jj_ls; 481 return false; 482 } 483 484 /** Get the next Token. */ 485 final public Token getNextToken() { 486 if (token.next != null) 487 token = token.next; 488 else 489 token = token.next = token_source.getNextToken(); 490 jj_ntk = -1; 491 jj_gen++; 492 return token; 493 } 494 495 /** Get the specific Token. */ 496 final public Token getToken(int index) { 497 Token t = token; 498 for (int i = 0; i < index; i++) { 499 if (t.next != null) 500 t = t.next; 501 else 502 t = t.next = token_source.getNextToken(); 503 } 504 return t; 505 } 506 507 private int jj_ntk() { 508 if ((jj_nt = token.next) == null) 509 return (jj_ntk = (token.next = token_source.getNextToken()).kind); 510 else 511 return (jj_ntk = jj_nt.kind); 512 } 513 private java.util.List<int[]> jj_expentries = new java.util.ArrayList<>(); 514 515 private int[] jj_expentry; 516 517 private int jj_kind = -1; 518 519 private int[] jj_lasttokens = new int[100]; 520 521 private int jj_endpos; 522 523 private void jj_add_error_token(int kind, int pos) { 524 if (pos >= 100) 525 return; 526 if (pos == jj_endpos + 1) { 527 jj_lasttokens[jj_endpos++] = kind; 528 } else if (jj_endpos != 0) { 529 jj_expentry = new int[jj_endpos]; 530 System.arraycopy(jj_lasttokens, 0, jj_expentry, 0, jj_endpos); 531 jj_entries_loop: 532 for (int[] jj_expentry1 : jj_expentries) { 533 if (jj_expentry1.length == jj_expentry.length) { 534 for (int i = 0; i < jj_expentry.length; i++) { 535 if (jj_expentry1[i] != jj_expentry[i]) { 536 continue jj_entries_loop; 537 } 538 } 539 jj_expentries.add(jj_expentry); 540 break; 541 } 542 } 543 if (pos != 0) 544 jj_lasttokens[(jj_endpos = pos) - 1] = kind; 545 } 546 } 547 548 /** Generate TokenException. */ 549 TokenException raiseTokenException() { 550 jj_expentries.clear(); 551 boolean[] la1tokens = new boolean[16]; 552 if (jj_kind >= 0) { 553 la1tokens[jj_kind] = true; 554 jj_kind = -1; 555 } 556 for (int i = 0; i < 5; i++) { 557 if (jj_la1[i] == jj_gen) { 558 for (int j = 0; j < 32; j++) { 559 if ((jj_la1_0[i] & (1 << j)) != 0) { 560 la1tokens[j] = true; 561 } 562 } 563 } 564 } 565 for (int i = 0; i < 16; i++) { 566 if (la1tokens[i]) { 567 jj_expentry = new int[1]; 568 jj_expentry[0] = i; 569 jj_expentries.add(jj_expentry); 570 } 571 } 572 jj_endpos = 0; 573 jj_rescan_token(); 574 jj_add_error_token(0, 0); 575 int[][] exptokseq = new int[jj_expentries.size()][]; 576 for (int i = 0; i < jj_expentries.size(); i++) { 577 exptokseq[i] = jj_expentries.get(i); 578 } 579 return new TokenException(token, exptokseq, tokenImage); 580 } 581 582 /** Enable tracing. */ 583 final public void enable_tracing() { 584 } 585 586 /** Disable tracing. */ 587 final public void disable_tracing() { 588 } 589 590 private void jj_rescan_token() { 591 jj_rescan = true; 592 for (int i = 0; i < 2; i++) { 593 try { 594 JJCalls p = jj_2_rtns[i]; 595 do { 596 if (p.gen > jj_gen) { 597 jj_la = p.arg; 598 jj_lastpos = jj_scanpos = p.first; 599 switch (i) { 600 case 0: 601 jj_3_1(); 602 break; 603 case 1: 604 jj_3_2(); 605 break; 606 } 607 } 608 p = p.next; 609 } while (p != null); 610 } catch (LookaheadSuccess ls) { 611 } 612 } 613 jj_rescan = false; 614 } 615 616 private void jj_save(int index, int xla) { 617 JJCalls p = jj_2_rtns[index]; 618 while (p.gen > jj_gen) { 619 if (p.next == null) { 620 p = p.next = new JJCalls(); 621 break; 622 } 623 p = p.next; 624 } 625 p.gen = jj_gen + xla - jj_la; 626 p.first = token; 627 p.arg = xla; 628 } 629 630 static final class JJCalls { 631 632 int gen; 633 634 Token first; 635 636 int arg; 637 638 JJCalls next; 639 640 } 641}