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