1 /* $Author: hansonr $ 2 * $Date: 2009-06-08 18:20:22 -0500 (Mon, 08 Jun 2009) $ 3 * $Revision: 10975 $ 4 * 5 * Copyright (C) 2002-2005 The Jmol Development Team 6 * 7 * Contact: jmol-developers@lists.sf.net 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 */ 23 24 package org.jmol.script; 25 26 import javajs.util.Lst; 27 import javajs.util.PT; 28 29 import java.util.Map; 30 31 import org.jmol.util.Edge; 32 import org.jmol.util.Logger; 33 import org.jmol.util.SimpleUnitCell; 34 35 import javajs.util.P3; 36 37 import org.jmol.viewer.Viewer; 38 import org.jmol.i18n.GT; 39 40 41 /** 42 * An abstract class subclassed by ScriptCompiler taking care of the second 43 * phase of syntax checking. After all the tokens are created, these methods 44 * ensure that they are in the proper order in terms of expressions, primarily. 45 * 46 * Here we are going from an "infix" to a "postfix" set of tokens and then back 47 * to infix for final storage. 48 * 49 */ 50 51 52 abstract class ScriptTokenParser { 53 54 protected Viewer vwr; 55 56 protected Map<String, Boolean> htUserFunctions; 57 58 protected String script; 59 protected boolean isStateScript; 60 61 protected short lineCurrent; 62 protected int iCommand; 63 64 protected int ichCurrentCommand, ichComment, ichEnd; 65 protected int ichToken; 66 67 protected T theToken; 68 protected T lastFlowCommand; 69 protected T tokenCommand; 70 protected T lastToken; 71 protected T tokenAndEquals; 72 73 protected int theTok; 74 protected int nTokens; 75 protected int tokCommand; 76 77 protected int ptNewSetModifier; 78 protected boolean isNewSet; 79 protected boolean haveMacro; 80 81 82 //---------------------------------------------------------------------------------------- 83 //---------------------------------------------------------------------------------------- 84 //---------------PHASE II -- TOKEN-BASED COMPILING --------------------------------------- 85 //---------------------------------------------------------------------------------------- 86 //---------------------------------------------------------------------------------------- 87 88 protected boolean logMessages = true; 89 90 protected T[] atokenInfix; 91 protected int itokenInfix; 92 93 protected boolean isSetBrace; 94 protected boolean isMathExpressionCommand; 95 protected boolean isSetOrDefine; 96 97 private Lst<T> ltokenPostfix; 98 99 protected boolean isEmbeddedExpression; 100 protected boolean isCommaAsOrAllowed; 101 102 private Object theValue; 103 compileExpressions()104 protected boolean compileExpressions() { 105 106 boolean isScriptExpression = ((tokCommand == T.script || tokCommand == T.macro) 107 && tokAt(2) == T.leftparen); 108 isEmbeddedExpression = (isScriptExpression 109 || (tokCommand != T.nada 110 && (tokCommand != T.function 111 && tokCommand != T.parallel 112 && tokCommand != T.trycmd 113 && tokCommand != T.catchcmd 114 || tokenCommand.intValue != Integer.MAX_VALUE) 115 && tokCommand != T.end 116 && !T.tokAttr(tokCommand, T.atomExpressionCommand) 117 && (nTokens > 2 || !T.tokAttr(tokCommand, T.implicitStringCommand) 118 ) 119 ) 120 ); 121 isMathExpressionCommand = (tokCommand == T.identifier 122 || isScriptExpression 123 || T.tokAttr(tokCommand, T.mathExpressionCommand)); 124 125 boolean checkExpression = isEmbeddedExpression 126 || (T.tokAttr(tokCommand, T.atomExpressionCommand)); 127 128 // $ at beginning disallow expression checking for center, delete, hide, or 129 // display commands 130 if (tokAt(1) == T.dollarsign 131 && T.tokAttr(tokCommand, T.atomExpressionCommand)) 132 checkExpression = false; 133 if (checkExpression && !compileExpression()) 134 return false; 135 136 // check statement length 137 138 int size = atokenInfix.length; 139 140 int nDefined = 0; 141 for (int i = 1; i < size; i++) { 142 if (tokAt(i) == T.define) 143 nDefined++; 144 } 145 146 size -= nDefined; 147 if (isNewSet) { 148 if (size == 1) { 149 atokenInfix[0] = T.tv(T.function, 0, atokenInfix[0].value); 150 isNewSet = false; 151 } 152 } 153 154 // must avoid roll-over to negative number in JavaScript 155 if ((isNewSet || isSetBrace) && ptNewSetModifier != Integer.MAX_VALUE && size < ptNewSetModifier + 2) { 156 if (!isNewSet || !haveMacro) 157 return commandExpected(); 158 htUserFunctions.put((String) atokenInfix[0].value, Boolean.TRUE); 159 } 160 return(size == 1 || !T.tokAttr(tokCommand, T.noArgs) ? true 161 : error(ERROR_badArgumentCount)); 162 } 163 164 compileExpression()165 protected boolean compileExpression() { 166 int firstToken = (isSetOrDefine && !isSetBrace ? 2 : 1); 167 ltokenPostfix = new Lst<T>(); 168 itokenInfix = 0; 169 T tokenBegin = null; 170 int tok = tokAt(1); 171 switch (tokCommand) { 172 case T.define: 173 int i = (tokAt(1) == T.define ? 2 : 1); 174 if (tokAt(i) == T.integer && tokAt(i + 1) == T.per && tokAt(i + 3) == T.opEQ) { 175 // @2.xxx = 176 // @@2.xxx = 177 tokCommand = T.set; 178 isSetBrace = true; 179 ptNewSetModifier = i + 3; 180 isMathExpressionCommand = true; 181 isEmbeddedExpression = true; 182 addTokenToPostfixToken(T.tokenSetProperty); 183 addTokenToPostfixToken(T.tokenExpressionBegin); 184 for (int j = 0; j++ <= i;) 185 addNextToken(); 186 addTokenToPostfixToken(T.tokenExpressionEnd); 187 firstToken = 0; 188 } 189 break; 190 case T.restrict: 191 if (tok == T.bonds) 192 firstToken = 2; 193 break; 194 case T.select: 195 switch(tok) { 196 case T.on: 197 case T.off: 198 tok = tokAt(++firstToken); 199 break; 200 } 201 //$FALL-THROUGH$ 202 case T.hide: 203 case T.display: 204 switch(tok) { 205 case T.add: 206 case T.remove: 207 tok = tokAt(++firstToken); 208 break; 209 } 210 if (tok == T.group && !T.tokAttr(tokAt(firstToken + 1), T.mathop)) 211 firstToken++; 212 } 213 for (int i = 0; i < firstToken && addNextToken(); i++) { 214 } 215 while (moreTokens()) { 216 if (isEmbeddedExpression) { 217 while (!isExpressionNext()) { 218 if (tokPeekIs(T.identifier) && !(tokCommand == T.load && itokenInfix == 1)) { 219 String name = (String) atokenInfix[itokenInfix].value; 220 T t = T.getTokenFromName(name); 221 if (t != null) 222 if (!isMathExpressionCommand && lastToken.tok != T.define 223 || (lastToken.tok == T.per || tokAt(itokenInfix + 1) == T.leftparen) 224 && !isUserFunction(name)) { 225 // Checking here for known token masquerading as identifier due to VAR definition. 226 // We reset it to its original mapping if it's a known token and: 227 // a) this isn't a math expression command, and not preceded by @, or 228 // b) it is preceded by "." or followed by "(" 229 // and it isn't the name of a user function 230 231 atokenInfix[itokenInfix] = t; 232 } 233 } 234 if (!addNextToken()) 235 break; 236 } 237 if (!moreTokens()) 238 break; 239 } 240 if (lastToken.tok == T.define) { 241 if (!clauseDefine(true, false)) 242 return false; 243 continue; 244 } 245 if (!isMathExpressionCommand) 246 addTokenToPostfixToken(tokenBegin = T.o(T.expressionBegin, "implicitExpressionBegin")); 247 if (!clauseOr(isCommaAsOrAllowed || !isMathExpressionCommand 248 && tokPeekIs(T.leftparen))) 249 return false; 250 if (!isMathExpressionCommand 251 && !(isEmbeddedExpression && lastToken == T.tokenCoordinateEnd)) { 252 addTokenToPostfixToken(T.tokenExpressionEnd); 253 } 254 if (moreTokens()) { 255 if (tokCommand != T.select && tokCommand != T.delete && !isEmbeddedExpression) 256 return error(ERROR_endOfExpressionExpected); 257 if (tokCommand == T.select) { 258 // advanced select, with two expressions, the first 259 // being an atom expression; the second being a property selector expression 260 tokenBegin.intValue = 0; 261 tokCommand = T.nada; 262 isEmbeddedExpression = true; 263 isMathExpressionCommand = true; 264 isCommaAsOrAllowed = false; 265 } 266 } 267 } 268 atokenInfix = ltokenPostfix.toArray(new T[ltokenPostfix.size()]); 269 return true; 270 } 271 isUserFunction(String name)272 protected boolean isUserFunction(String name) { 273 name = name.toLowerCase(); 274 return (!isStateScript && (vwr.isFunction(name) || htUserFunctions.containsKey(name))); 275 } 276 isExpressionNext()277 private boolean isExpressionNext() { 278 return tokPeekIs(T.leftbrace) 279 && !(tokAt(itokenInfix + 1) == T.string 280 && tokAt(itokenInfix + 2) == T.colon) 281 || !isMathExpressionCommand && tokPeekIs(T.leftparen); 282 } 283 tokenAttr(T token, int tok)284 protected static boolean tokenAttr(T token, int tok) { 285 return token != null && T.tokAttr(token.tok, tok); 286 } 287 moreTokens()288 private boolean moreTokens() { 289 return (itokenInfix < atokenInfix.length); 290 } 291 tokAt(int i)292 protected int tokAt(int i) { 293 return (i < atokenInfix.length ? atokenInfix[i].tok : T.nada); 294 } 295 tokPeek()296 private int tokPeek() { 297 return (itokenInfix >= atokenInfix.length ? T.nada 298 : atokenInfix[itokenInfix].tok); 299 } 300 tokPeekIs(int tok)301 private boolean tokPeekIs(int tok) { 302 return (tokAt(itokenInfix) == tok); 303 } 304 intPeek()305 private int intPeek() { 306 return (itokenInfix >= atokenInfix.length ? Integer.MAX_VALUE 307 : atokenInfix[itokenInfix].intValue); 308 } 309 valuePeek()310 private Object valuePeek() { 311 return (moreTokens() ? atokenInfix[itokenInfix].value : ""); 312 } 313 314 /** 315 * increments the pointer; does NOT set theToken or theValue 316 * @return the next token 317 */ tokenNext()318 private T tokenNext() { 319 return (itokenInfix >= atokenInfix.length ? null 320 : atokenInfix[itokenInfix++]); 321 } 322 tokenNextTok(int tok)323 private boolean tokenNextTok(int tok) { 324 T token = tokenNext(); 325 return (token != null && token.tok == tok); 326 } 327 returnToken()328 private boolean returnToken() { 329 itokenInfix--; 330 return false; 331 } 332 333 /** 334 * gets the next token and sets global theToken and theValue 335 * @return the next token 336 */ getToken()337 private T getToken() { 338 theValue = ((theToken = tokenNext()) == null ? null : theToken.value); 339 return theToken; 340 } 341 getNumericalToken()342 private boolean getNumericalToken() { 343 return (getToken() != null 344 && (theToken.tok == T.integer || theToken.tok == T.decimal)); 345 } 346 floatValue()347 private float floatValue() { 348 switch (theToken.tok) { 349 case T.integer: 350 return theToken.intValue; 351 case T.decimal: 352 return ((Float) theValue).floatValue(); 353 } 354 return 0; 355 } 356 addTokenToPostfix(int tok, Object value)357 private boolean addTokenToPostfix(int tok, Object value) { 358 return addTokenToPostfixToken(T.o(tok, value)); 359 } 360 addTokenToPostfixInt(int tok, int intValue, Object value)361 private boolean addTokenToPostfixInt(int tok, int intValue, Object value) { 362 return addTokenToPostfixToken(T.tv(tok, intValue, value)); 363 } 364 addTokenToPostfixToken(T token)365 private boolean addTokenToPostfixToken(T token) { 366 if (token == null) 367 return false; 368 if (logMessages) 369 Logger.debug("addTokenToPostfix" + token); 370 if (token.tok == T.leftsquare && (lastToken.tok == T.per || lastToken.tok == T.perper)) { 371 // new notation 372 int ipt = ltokenPostfix.size() - 1; 373 ltokenPostfix.removeItemAt(ipt); 374 ltokenPostfix.addLast(T.tokenRightParen); 375 int pcount = 0; 376 int tok; 377 for (int i = ltokenPostfix.size(); --i >= 0 && pcount >= 0;) { 378 switch (tok = ltokenPostfix.get(i).tok) { 379 case T.rightparen: 380 case T.rightsquare: 381 pcount++; 382 break; 383 case T.leftparen: 384 case T.leftsquare: 385 pcount--; 386 int tok2; 387 if (pcount == 1 && (tok2 = ltokenPostfix.get(i - 1).tok) != T.rightparen && tok2 != T.rightsquare) { 388 ipt = (tok == T.leftsquare ? i - 1 : i); 389 pcount = -10; 390 } 391 break; 392 default: 393 tok2 = (i == 0 ? T.nada : ltokenPostfix.get(i - 1).tok); 394 if (tok2 == T.per || tok2 == T.perper) { 395 ipt = i - 1; 396 break; 397 } 398 if (i == ipt - 1) { 399 ipt = i; 400 pcount = -10; 401 } 402 break; 403 } 404 } 405 if (pcount == -10) { 406 ltokenPostfix.add(ipt, T.tokenLeftParen); 407 } 408 } 409 ltokenPostfix.addLast(token); 410 lastToken = token; 411 return true; 412 } 413 addNextToken()414 private boolean addNextToken() { 415 return addTokenToPostfixToken(tokenNext()); 416 } 417 addNextTokenIf(int tok)418 private boolean addNextTokenIf(int tok) { 419 return (tokPeekIs(tok) && addNextToken()); 420 } 421 addSubstituteTokenIf(int tok, T token)422 private boolean addSubstituteTokenIf(int tok, T token) { 423 if (!tokPeekIs(tok)) 424 return false; 425 itokenInfix++; 426 return addTokenToPostfixToken(token); 427 } 428 429 boolean haveString; 430 clauseOr(boolean allowCommaAsOr)431 private boolean clauseOr(boolean allowCommaAsOr) { 432 haveString = false; 433 if (!clauseAnd()) 434 return false; 435 if (isEmbeddedExpression && lastToken.tok == T.expressionEnd) 436 return true; 437 438 //for simplicity, giving XOR (toggle) same precedence as OR 439 //OrNot: First OR, but if that makes no change, then NOT (special toggle) 440 int tok; 441 while ((tok = tokPeek())== T.opOr || tok == T.opXor 442 || tok==T.opToggle|| allowCommaAsOr && tok == T.comma) { 443 if (tok == T.comma && !haveString) 444 addSubstituteTokenIf(T.comma, T.tokenOr); 445 else 446 addNextToken(); 447 if (!clauseAnd()) 448 return false; 449 if (allowCommaAsOr && (lastToken.tok == T.rightbrace || lastToken.tok == T.bitset)) 450 haveString = true; 451 } 452 return true; 453 } 454 clauseAnd()455 private boolean clauseAnd() { 456 if (!clauseNot()) 457 return false; 458 if (isEmbeddedExpression && lastToken.tok == T.expressionEnd) 459 return true; 460 while (tokPeekIs(T.opAnd)) { 461 addNextToken(); 462 if (!clauseNot()) 463 return false; 464 } 465 return true; 466 } 467 468 // for RPN processor, not reversed clauseNot()469 private boolean clauseNot() { 470 if (tokPeekIs(T.opNot)) { 471 addNextToken(); 472 return clauseNot(); 473 } 474 return (clausePrimitive()); 475 } 476 clausePrimitive()477 private boolean clausePrimitive() { 478 int tok = tokPeek(); 479 switch (tok) { 480 case T.spacebeforesquare: 481 itokenInfix++; 482 return clausePrimitive(); 483 case T.nada: 484 return error(ERROR_endOfCommandUnexpected); 485 case T.all: 486 case T.bitset: 487 case T.divide: 488 case T.helix: 489 case T.helix310: 490 case T.helixalpha: 491 case T.helixpi: 492 case T.isaromatic: 493 case T.none: 494 case T.sheet: 495 // nothing special 496 return addNextToken(); 497 case T.string: 498 haveString = true; 499 return addNextToken(); 500 case T.decimal: 501 // create a file_model integer as part of the token 502 return addTokenToPostfixInt(T.spec_model2, fixModelSpec(getToken()), theValue); 503 case T.cell: 504 case T.centroid: 505 return clauseCell(tok); 506 case T.connected: 507 case T.polyhedra: 508 return clauseConnected(tok == T.polyhedra); 509 case T.search: 510 case T.smiles: 511 return clauseSubstructure(); 512 case T.within: 513 case T.contact: 514 return clauseWithin(tok == T.within); 515 case T.define: 516 return clauseDefine(false, false); 517 case T.bonds: 518 case T.measure: 519 addNextToken(); 520 if (tokPeekIs(T.bitset)) 521 addNextToken(); 522 else if (tokPeekIs(T.define)) 523 return clauseDefine(false, false); 524 return true; 525 case T.leftparen: 526 addNextToken(); 527 if (!clauseOr(true)) 528 return false; 529 if (!addNextTokenIf(T.rightparen)) 530 return errorStr(ERROR_tokenExpected, ")"); 531 return checkForItemSelector(true); 532 case T.leftbrace: 533 return checkForCoordinate(isMathExpressionCommand); 534 default: 535 // may be a residue specification 536 if (clauseResidueSpec()) 537 return true; 538 if (isError()) 539 return false; 540 if (T.tokAttr(tok, T.atomproperty)) { 541 int itemp = itokenInfix; 542 boolean isOK = clauseComparator(true); 543 if (isOK || itokenInfix != itemp) 544 return isOK; 545 if (tok == T.substructure) { 546 return clauseSubstructure(); 547 } 548 549 } 550 //if (tok != Token.integer && !Token.tokAttr(tok, Token.predefinedset)) 551 //break; 552 return addNextToken(); 553 554 } 555 // return error(ERROR_unrecognizedExpressionToken, "" + valuePeek()); 556 } 557 checkForCoordinate(boolean isImplicitExpression)558 private boolean checkForCoordinate(boolean isImplicitExpression) { 559 /* 560 * A bit tricky here: we have three contexts for braces -- 561 * 562 * 1) expressionCommands SELECT, RESTRICT, DEFINE, 563 * DISPLAY, HIDE, CENTER, and SUBSET 564 * 565 * 2) embeddedExpression commands such as DRAW and ISOSURFACE 566 * 567 * 3) IF and SET 568 * 569 * Then, within these, we have the possibility that we are 570 * looking at a coordinate {0 0 0} (with or without commas, and 571 * possibly fractional, {1/2 1/2 1}, and possibly a plane Point4f 572 * definition, {a b c d}) or an expression. 573 * 574 * We assume an expression initially and then adjust accordingly 575 * if it turns out this is a coordinate. 576 * 577 * Note that due to the nuances of how expressions such as (1-4) are 578 * reported as special codes, Eval must still interpret these 579 * carefully. This could be corrected for here, I think. 580 * 581 */ 582 boolean isCoordinate = false; 583 int pt = ltokenPostfix.size(); 584 if (isImplicitExpression) { 585 addTokenToPostfixToken(T.tokenExpressionBegin); 586 tokenNext(); 587 } else if (isEmbeddedExpression) { 588 tokenNext(); 589 pt--; 590 } else { 591 addNextToken(); 592 } 593 boolean isHash = tokPeekIs(T.string); 594 if (isHash) { 595 isImplicitExpression = false; 596 returnToken(); 597 ltokenPostfix.removeItemAt(ltokenPostfix.size() - 1); 598 addNextToken(); 599 int nBrace = 1; 600 while (nBrace != 0) { 601 if (tokPeekIs(T.leftbrace)) { 602 if (isExpressionNext()) { 603 addTokenToPostfixToken(T.o(T.expressionBegin, 604 "implicitExpressionBegin")); 605 if (!clauseOr(false)) // changed to FALSE 10/20 because @({"center":{0.0 0.0 0.0}, "xxx"...}} failed 606 return false; 607 if (lastToken != T.tokenCoordinateEnd) { 608 addTokenToPostfixToken(T.tokenExpressionEnd); 609 } 610 } else { 611 nBrace++; 612 } 613 } 614 if (tokPeekIs(T.rightbrace)) 615 nBrace--; 616 addNextToken(); 617 } 618 } else { 619 if (!tokPeekIs(T.rightbrace) && !clauseOr(false)) 620 return false; 621 int n = 1; 622 while (!tokPeekIs(T.rightbrace)) { 623 boolean haveComma = addNextTokenIf(T.comma); 624 if (!clauseOr(false)) 625 return (haveComma || n < 3 ? false : errorStr(ERROR_tokenExpected, "}")); 626 n++; 627 } 628 isCoordinate = (n >= 2); // could be {1 -2 3} 629 } 630 if (isCoordinate && (isImplicitExpression || isEmbeddedExpression)) { 631 ltokenPostfix.set(pt, T.tokenCoordinateBegin); 632 addTokenToPostfixToken(T.tokenCoordinateEnd); 633 tokenNext(); 634 } else if (isImplicitExpression) { 635 addTokenToPostfixToken(T.tokenExpressionEnd); 636 tokenNext(); 637 } else if (isEmbeddedExpression) { 638 if (!isHash) 639 tokenNext(); 640 } else { 641 addNextToken(); 642 } 643 return checkForItemSelector(!isHash); 644 } 645 checkForItemSelector(boolean allowNumeric)646 private boolean checkForItemSelector(boolean allowNumeric) { 647 // {x[1]} @{x}[1][3] (atomno=3)[2][5] 648 int tok; 649 if ((tok = tokAt(itokenInfix + 1)) == T.leftsquare 650 || allowNumeric && tok == T.leftbrace) 651 return true; // [[, as in a matrix or [{ ... not totally acceptable! 652 653 // the real problem is that after an expression you can have 654 while (true) {//for (int i = 0; i < (allowNumeric ? 2 : 1); i++) { 655 if (!addNextTokenIf(T.leftsquare)) 656 break; 657 if (!clauseItemSelector()) 658 return false; 659 if (!addNextTokenIf(T.rightsquare)) 660 return errorStr(ERROR_tokenExpected, "]"); 661 } 662 return true; 663 } 664 clauseWithin(boolean isWithin)665 private boolean clauseWithin(boolean isWithin) { 666 667 // // contact(distance, {}, {}) // default 100 for distance 668 // within ( plane, planeExpression) 669 // within ( hkl, hklExpression) 670 // within ( distance, plane, planeExpression) 671 // within ( distance, hkl, hklExpression) 672 // within ( distance, coord, point) 673 // within ( distance, point) 674 // within ( distance, $surfaceId) 675 // within ( distance, orClause) 676 // within ( group|branch|etc, ....) 677 // within ( distance, group, ....) 678 // within ( annotation, "xxxx") 679 680 addNextToken(); 681 if (!addNextTokenIf(T.leftparen)) 682 return false; 683 if (getToken() == null) 684 return false; 685 float distance = Float.MAX_VALUE; 686 String key = null; 687 boolean allowComma = isWithin; 688 int tok; 689 int tok0 = theToken.tok; 690 if (!isWithin) { 691 tok = -1; 692 for (int i = itokenInfix; tok != T.nada; i++) { 693 switch (tok = tokAt(i)) { 694 case T.comma: 695 tok = T.nada; 696 break; 697 case T.leftbrace: 698 case T.leftparen: 699 case T.rightparen: 700 distance = 100; 701 returnToken(); 702 tok0 = tok = T.nada; 703 break; 704 } 705 } 706 } 707 switch (tok0) { 708 case T.minus: 709 if (getToken() == null) 710 return false; 711 if (theToken.tok != T.integer) 712 return error(ERROR_numberExpected); 713 distance = -theToken.intValue; 714 break; 715 case T.integer: 716 case T.decimal: 717 distance = floatValue(); 718 break; 719 case T.define: 720 addTokenToPostfixToken(theToken); 721 if (!clauseDefine(true, false)) 722 return false; 723 key = ""; 724 allowComma = false; 725 break; 726 } 727 if (isWithin && distance == Float.MAX_VALUE) 728 switch (tok0) { 729 case T.define: 730 break; 731 case T.centroid: 732 case T.cell: 733 addTokenToPostfix(T.string, theValue); 734 clauseCell(T.point3f); 735 key = ""; 736 break; 737 case T.dssr: 738 case T.rna3d: 739 case T.search: 740 case T.smiles: 741 case T.substructure: 742 case T.domains: 743 case T.validation: 744 addTokenToPostfix(T.string, theValue); 745 if (!addNextTokenIf(T.comma)) 746 return false; 747 allowComma = false; 748 tok = tokPeek(); 749 switch (tok) { 750 case T.nada: 751 return false; 752 case T.string: 753 addNextToken(); 754 key = ""; 755 break; 756 case T.define: 757 if (!clauseDefine(false, true)) 758 return false; 759 key = ""; 760 break; 761 default: 762 return false; 763 } 764 break; 765 case T.branch: 766 allowComma = false; 767 //$FALL-THROUGH$ 768 case T.atomtype: 769 case T.atomname: 770 case T.basepair: 771 case T.boundbox: 772 case T.chain: 773 case T.coord: 774 case T.element: 775 case T.group: 776 case T.unitcell: 777 case T.helix: 778 case T.model: 779 case T.molecule: 780 case T.plane: 781 case T.hkl: 782 case T.polymer: 783 case T.sequence: 784 case T.sheet: 785 case T.site: 786 case T.structure: 787 case T.string: 788 case T.vanderwaals: 789 key = (String) theValue; 790 break; 791 default: 792 key = ((String) theValue).toLowerCase(); 793 break; 794 } 795 if (key == null) 796 addTokenToPostfix(T.decimal, Float.valueOf(distance)); 797 else if (key.length() > 0) 798 addTokenToPostfix(T.string, key); 799 boolean done = false; 800 while (!done) { 801 if (tok0 != T.nada && !addNextTokenIf(T.comma)) 802 break; 803 if (tok0 == T.nada) 804 tok0 = T.contact; 805 boolean isCoordOrPlane = false; 806 tok = tokPeek(); 807 if (isWithin) { 808 switch (tok0) { 809 case T.integer: 810 case T.decimal: 811 if (tok == T.on || tok == T.off) { 812 addTokenToPostfixToken(getToken()); 813 if (!addNextTokenIf(T.comma)) 814 break; 815 tok = tokPeek(); 816 } 817 break; 818 } 819 if (key == null) { 820 switch (tok) { 821 case T.hkl: 822 case T.coord: 823 case T.plane: 824 isCoordOrPlane = true; 825 addNextToken(); 826 break; 827 case T.dollarsign: 828 getToken(); 829 getToken(); 830 addTokenToPostfix(T.string, "$" + theValue); 831 done = true; 832 break; 833 case T.group: 834 case T.vanderwaals: 835 case T.unitcell: 836 getToken(); 837 addTokenToPostfix(T.string, T.nameOf(tok)); 838 break; 839 case T.leftbrace: 840 returnToken(); 841 isCoordOrPlane = true; 842 addTokenToPostfixToken(T 843 .getTokenFromName(distance == Float.MAX_VALUE ? "plane" 844 : "coord")); 845 } 846 if (!done) 847 addNextTokenIf(T.comma); 848 } 849 } 850 tok = tokPeek(); 851 if (done) 852 break; 853 if (isCoordOrPlane) { 854 while (!tokPeekIs(T.rightparen)) { 855 switch (tokPeek()) { 856 case T.nada: 857 return error(ERROR_endOfCommandUnexpected); 858 case T.leftparen: 859 addTokenToPostfixToken(T.tokenExpressionBegin); 860 addNextToken(); 861 if (!clauseOr(false)) 862 return errorIntStr2(ERROR_unrecognizedParameter, "WITHIN", ": ?"); 863 if (!addNextTokenIf(T.rightparen)) 864 return errorStr(ERROR_tokenExpected, ", / )"); 865 addTokenToPostfixToken(T.tokenExpressionEnd); 866 break; 867 case T.define: 868 if (!clauseDefine(false, false)) 869 return false; 870 break; 871 default: 872 addTokenToPostfixToken(getToken()); 873 } 874 } 875 } else if (!clauseOr(allowComma)) {// *expression* return error(ERROR_badArgumentCount); 876 } 877 } 878 if (!addNextTokenIf(T.rightparen)) 879 return errorStr(ERROR_tokenExpected, ")"); 880 return true; 881 } 882 clauseConnected(boolean isPolyhedra)883 private boolean clauseConnected(boolean isPolyhedra) { 884 addNextToken(); 885 // connected (1,3, single, .....) 886 if (!addNextTokenIf(T.leftparen)) { 887 addTokenToPostfixToken(T.tokenLeftParen); 888 addTokenToPostfixToken(T.tokenRightParen); 889 return true; 890 } 891 while (true) { 892 if (addNextTokenIf(T.integer)) { 893 if (!addNextTokenIf(T.comma)) { 894 break; 895 } 896 if (isPolyhedra) { 897 returnToken(); 898 break; 899 } 900 } else if (isPolyhedra && 901 (addNextTokenIf(T.string) || addNextTokenIf(T.identifier))) { 902 break; 903 } 904 905 if (addNextTokenIf(T.integer)) 906 if (!addNextTokenIf(T.comma)) 907 break; 908 if (addNextTokenIf(T.decimal)) 909 if (!addNextTokenIf(T.comma)) 910 break; 911 if (addNextTokenIf(T.decimal)) 912 if (!addNextTokenIf(T.comma)) 913 break; 914 Object o = getToken().value; 915 String strOrder = (o instanceof String ? (String) o : " "); 916 int intType = ScriptParam.getBondOrderFromString(strOrder); 917 if (intType == Edge.BOND_ORDER_NULL) { 918 returnToken(); 919 } else { 920 addTokenToPostfix(T.string, strOrder); 921 if (!addNextTokenIf(T.comma)) 922 break; 923 } 924 if (addNextTokenIf(T.rightparen)) 925 return true; 926 if (!clauseOr(tokPeekIs(T.leftparen))) // *expression* 927 return false; 928 if (addNextTokenIf(T.rightparen)) 929 return true; 930 if (!addNextTokenIf(T.comma)) 931 return false; 932 if (!clauseOr(tokPeekIs(T.leftparen))) // *expression* 933 return false; 934 935 break; 936 } 937 if (!addNextTokenIf(T.rightparen)) 938 return errorStr(ERROR_tokenExpected, ")"); 939 return true; 940 } 941 clauseSubstructure()942 private boolean clauseSubstructure() { 943 addNextToken(); 944 if (!addNextTokenIf(T.leftparen)) 945 return false; 946 if (tokPeekIs(T.define)) { 947 if (!clauseDefine(false, true)) 948 return false; 949 } else if (!addNextTokenIf(T.string)) { 950 return errorStr(ERROR_tokenExpected, "\"...\""); 951 } 952 if (addNextTokenIf(T.comma)) 953 if (!clauseOr(tokPeekIs(T.leftparen))) // *expression* 954 return false; 955 if (!addNextTokenIf(T.rightparen)) 956 return errorStr(ERROR_tokenExpected, ")"); 957 return true; 958 } 959 clauseItemSelector()960 private boolean clauseItemSelector() { 961 int tok; 962 int nparen = 0; 963 while ((tok = tokPeek()) != T.nada && tok != T.rightsquare) { 964 addNextToken(); 965 if (tok == T.leftsquare) 966 nparen++; 967 if (tokPeek() == T.rightsquare && nparen-- > 0) 968 addNextToken(); 969 } 970 return true; 971 } 972 clauseComparator(boolean isOptional)973 private boolean clauseComparator(boolean isOptional) { 974 T tokenAtomProperty = tokenNext(); 975 T tokenComparator = tokenNext(); 976 if (!tokenAttr(tokenComparator, T.comparator)) { 977 if (!isOptional) 978 return errorStr(ERROR_tokenExpected, "== != < > <= >="); 979 if (tokenComparator != null) 980 returnToken(); 981 returnToken(); 982 return false; 983 } 984 if (tokenAttr(tokenAtomProperty, T.strproperty) 985 && tokenComparator.tok != T.opEQ 986 && tokenComparator.tok != T.opLIKE 987 && tokenComparator.tok != T.opNE) 988 return errorStr(ERROR_tokenExpected, "== !="); 989 if (tokPeek() == T.leftsquare) { 990 getToken(); 991 addTokenToPostfixToken(T.tokenLeftParen); 992 while (true) { 993 if (!addCompare(tokenAtomProperty, tokenComparator)) 994 return false; 995 if (tokPeek() == T.comma) 996 getToken(); 997 else if (tokPeek() == T.rightsquare) 998 break; 999 addTokenToPostfixToken(tokenComparator.tok == T.opNE ? T.tokenAnd : T.tokenOr); 1000 } 1001 getToken(); 1002 addTokenToPostfixToken(T.tokenRightParen); 1003 return true; 1004 } 1005 return addCompare(tokenAtomProperty, tokenComparator); 1006 } 1007 addCompare(T tokenAtomProperty, T tokenComparator)1008 private boolean addCompare(T tokenAtomProperty, T tokenComparator) { 1009 if (getToken() == null) 1010 return errorStr(ERROR_unrecognizedExpressionToken, "" + valuePeek()); 1011 boolean isNegative = (theToken.tok == T.minus); 1012 if (isNegative && getToken() == null) 1013 return error(ERROR_numberExpected); 1014 switch (theToken.tok) { 1015 case T.integer: 1016 case T.decimal: 1017 case T.identifier: 1018 case T.string: 1019 case T.leftbrace: 1020 case T.define: 1021 break; 1022 default: 1023 if (!T.tokAttr(theToken.tok, T.misc)) 1024 return error(ERROR_numberOrVariableNameExpected); 1025 } 1026 addTokenToPostfixInt(tokenComparator.tok, tokenAtomProperty.tok, 1027 tokenComparator.value + (isNegative ? " -" : "")); 1028 if (tokenAtomProperty.tok == T.property) 1029 addTokenToPostfixToken(tokenAtomProperty); 1030 if (theToken.tok == T.leftbrace) { 1031 returnToken(); 1032 return clausePrimitive(); 1033 } 1034 addTokenToPostfixToken(theToken); 1035 if (theToken.tok == T.define) 1036 return clauseDefine(true, false); 1037 return true; 1038 } 1039 clauseCell(int tok)1040 private boolean clauseCell(int tok) { 1041 P3 cell = new P3(); 1042 tokenNext(); // CELL 1043 if (tok != T.point3f) { 1044 if (!tokenNextTok(T.opEQ)) // = 1045 return errorStr(ERROR_tokenExpected, "="); 1046 } 1047 if (getToken() == null) 1048 return error(ERROR_coordinateExpected); 1049 // 555 = {1 1 1} 1050 //Token coord = tokenNext(); // 555 == {1 1 1} 1051 if (theToken.tok == T.integer) { 1052 SimpleUnitCell.ijkToPoint3f(theToken.intValue, cell, 1, 0); 1053 } else { 1054 if (theToken.tok != T.leftbrace || !getNumericalToken()) 1055 return error(ERROR_coordinateExpected); // i 1056 cell.x = floatValue(); 1057 if (tokPeekIs(T.comma)) // , 1058 tokenNext(); 1059 if (!getNumericalToken()) 1060 return error(ERROR_coordinateExpected); // j 1061 cell.y = floatValue(); 1062 if (tokPeekIs(T.comma)) // , 1063 tokenNext(); 1064 if (!getNumericalToken() || !tokenNextTok(T.rightbrace)) 1065 return error(ERROR_coordinateExpected); // k 1066 cell.z = floatValue(); 1067 } 1068 return addTokenToPostfix(tok, cell); 1069 } 1070 clauseDefine(boolean haveToken, boolean forceString)1071 private boolean clauseDefine(boolean haveToken, boolean forceString) { 1072 if (!haveToken) { 1073 T token = tokenNext(); 1074 if (forceString) // we know it is @, this forces string type 1075 token = T.tokenDefineString; 1076 addTokenToPostfixToken(token); 1077 } 1078 if (tokPeekIs(T.nada)) 1079 return error(ERROR_endOfCommandUnexpected); 1080 // we allow @x[1], which compiles as {@x}[1], not @{x[1]} 1081 // otherwise [1] gets read as a general atom name selector 1082 if (!addSubstituteTokenIf(T.leftbrace, T.tokenExpressionBegin)) { 1083 if (tokPeek() == T.define) 1084 addNextToken(); 1085 return addNextToken() && checkForItemSelector(true); 1086 } 1087 while (moreTokens() && !tokPeekIs(T.rightbrace)) { 1088 if (tokPeekIs(T.leftbrace)) { 1089 if (!checkForCoordinate(true)) 1090 return false; 1091 } else { 1092 addNextToken(); 1093 } 1094 } 1095 return addSubstituteTokenIf(T.rightbrace, T.tokenExpressionEnd) 1096 && checkForItemSelector(true); 1097 } 1098 1099 private boolean residueSpecCodeGenerated; 1100 generateResidueSpecCode(T token)1101 private boolean generateResidueSpecCode(T token) { 1102 if (residueSpecCodeGenerated) 1103 addTokenToPostfixToken(T.tokenAndSpec); 1104 addTokenToPostfixToken(token); 1105 residueSpecCodeGenerated = true; 1106 return true; 1107 } 1108 clauseResidueSpec()1109 private boolean clauseResidueSpec() { 1110 int tok = tokPeek(); 1111 residueSpecCodeGenerated = false; 1112 boolean checkResNameSpec = false; 1113 switch (tok) { 1114 case T.nada: 1115 // terminal 1116 case T.dna: 1117 case T.rna: 1118 return false; 1119 case T.integer: 1120 // select 33 1121 // select 33-35 1122 case T.colon: 1123 // select :a 1124 case T.percent: 1125 // select %1 1126 case T.inscode: 1127 // sequence code precompiled 1128 break; 1129 case T.times: 1130 // all 1131 case T.leftsquare: 1132 // [ala] 1133 case T.identifier: 1134 // ala 1135 checkResNameSpec = true; 1136 break; 1137 default: 1138 if (T.tokAttr(tok, T.comparator)) 1139 return false; 1140 String str = "" + valuePeek(); 1141 checkResNameSpec = (str.length() == 2 || str.length() == 3); 1142 // note: there are many groups that could 1143 // in principle be here, for example: 1144 // "AND" "SET" "TO*" 1145 // these need to have attribute expression to be here 1146 // but then there are FX FY FZ UX UY UZ .. 1147 if (!checkResNameSpec) 1148 return false; 1149 } 1150 boolean specSeen = false; 1151 if (checkResNameSpec) { 1152 if (!clauseResNameSpec()) 1153 return false; 1154 specSeen = true; 1155 tok = tokPeek(); 1156 } 1157 if (tok == T.integer || tok == T.times || tok == T.inscode) { 1158 // [ala]33 1159 // ala33 1160 // [ala]* 1161 // [ala]<precompiled seqcode 1162 if (!clauseSequenceSpec()) 1163 return false; 1164 specSeen = true; 1165 tok = tokPeek(); 1166 } 1167 if (tok == T.colon 1168 // BH 1/19/15 reduced allowance here -- just too much possible 1169 // that is undocumented, especially with multiple-character chains 1170 // || tok == T.times 1171 // || theToken.tok == T.rightsquare && 1172 // (tok == T.identifier 1173 // || tok == T.x || tok == T.y || tok == T.z || tok == T.w) 1174 // || tok == T.integer && !wasInteger 1175 ) { 1176 if (!clauseChainSpec(tok)) 1177 return false; 1178 specSeen = true; 1179 tok = tokPeek(); 1180 } 1181 if (tok == T.per) { 1182 if (!clauseAtomSpec()) 1183 return false; 1184 specSeen = true; 1185 tok = tokPeek(); 1186 } 1187 if (tok == T.percent) { 1188 if (!clauseAlternateSpec()) 1189 return false; 1190 specSeen = true; 1191 tok = tokPeek(); 1192 } 1193 if (tok == T.divide) { 1194 // BH 1/19/2015: was || tok == T.colon here, but then that would 1195 // allow undocumented [ala]:a:1 to be the same as [ala]:a/1 ?? 1196 if (!clauseModelSpec()) 1197 return false; 1198 specSeen = true; 1199 tok = tokPeek(); 1200 } 1201 if (!specSeen) 1202 return error(ERROR_residueSpecificationExpected); 1203 if (!residueSpecCodeGenerated) { 1204 // nobody generated any code, so everybody was a * (or equivalent) 1205 addTokenToPostfixToken(T.tokenAll); 1206 } 1207 return true; 1208 } 1209 1210 /** 1211 * [a] or just a 1212 * @return true if handled 1213 */ clauseResNameSpec()1214 private boolean clauseResNameSpec() { 1215 getToken(); 1216 int tok = tokPeek(); 1217 switch (theToken.tok) { 1218 case T.times: 1219 return true; 1220 case T.leftsquare: 1221 String strSpec = ""; 1222 while (getToken() != null && theToken.tok != T.rightsquare) 1223 strSpec += theValue; 1224 if (theToken == null) 1225 return false; 1226 if (strSpec == "") 1227 return true; 1228 int pt; 1229 return (strSpec.length() > 0 && (pt = strSpec.indexOf("*")) >= 0 1230 && pt != strSpec.length() - 1 ? error(ERROR_residueSpecificationExpected) 1231 : generateResidueSpecCode(T.o(T.spec_name_pattern, strSpec.toUpperCase()))); 1232 default: 1233 if (T.tokAttr(tok, T.comparator)) { 1234 // a variable, not a name. For example: 1235 // a > 3 1236 // _e = 55 1237 returnToken(); 1238 return false; 1239 } 1240 //check for a * in the next token, which 1241 //would indicate this must be a name with wildcard 1242 String res = (String) theValue; 1243 if (tok == T.times) { 1244 res = theValue + "*"; 1245 getToken(); 1246 } 1247 return generateResidueSpecCode(T.o(T.identifier, res)); 1248 } 1249 } 1250 clauseSequenceSpec()1251 private boolean clauseSequenceSpec() { 1252 if (tokPeek() == T.times) 1253 return (getToken() != null); // true 1254 T seqToken = getSequenceCode(false); 1255 if (seqToken == null) 1256 return false; 1257 int tok = tokPeek(); 1258 if (tok == T.minus || tok == T.integer && intPeek() < 0) { 1259 if (tok == T.minus) { 1260 tokenNext(); 1261 } else { 1262 // hyphen masquerading as neg int 1263 int i = -intPeek(); 1264 tokenNext().intValue = i; 1265 returnToken(); 1266 } 1267 seqToken.tok = T.spec_seqcode_range; 1268 generateResidueSpecCode(seqToken); 1269 return addTokenToPostfixToken(getSequenceCode(true)); 1270 } 1271 return generateResidueSpecCode(seqToken); 1272 } 1273 getSequenceCode(boolean isSecond)1274 private T getSequenceCode(boolean isSecond) { 1275 int seqcode = Integer.MAX_VALUE; 1276 int seqvalue = Integer.MAX_VALUE; 1277 switch (tokPeek()) { 1278 case T.inscode: 1279 seqcode = tokenNext().intValue; 1280 break; 1281 case T.integer: 1282 seqvalue = tokenNext().intValue; 1283 break; 1284 default: 1285 if (!isSecond) 1286 return null; 1287 // can have open-ended range 1288 // select 3- 1289 } 1290 return T.tv(T.spec_seqcode, seqvalue, Integer.valueOf(seqcode)); 1291 } 1292 1293 /** 1294 * [:] [chars] 1295 * 1296 * [:] ["chars"] 1297 * 1298 * [:] [*] 1299 * 1300 * [:] [0-9] 1301 * 1302 * [:] [?] 1303 * 1304 * [:] (empty chain) 1305 * 1306 * @param tok 1307 * @return true if chain handled 1308 */ clauseChainSpec(int tok)1309 private boolean clauseChainSpec(int tok) { 1310 tokenNext(); 1311 tok = tokPeek(); 1312 String strChain; 1313 if (isTerminator(tok)) { 1314 strChain = " "; 1315 } else { 1316 switch (tok) { 1317 case T.times: 1318 return (getToken() != null); // true 1319 case T.integer: 1320 getToken(); 1321 int val = theToken.intValue; 1322 if (val < 0 || val > 9999) 1323 return error(ERROR_invalidChainSpecification); 1324 strChain = "" + val; 1325 break; 1326 case T.string: 1327 vwr.getChainID("a", true); // forces chain case 1328 //$FALL-THROUGH$ 1329 default: 1330 strChain = "" + getToken().value; 1331 break; 1332 } 1333 if (strChain.length() == 0) 1334 strChain = " "; 1335 else if (strChain.equals("?")) 1336 return true; 1337 } 1338 int chain = vwr.getChainID(strChain, false); 1339 return generateResidueSpecCode(T.tv(T.spec_chain, chain, "spec_chain")); 1340 } 1341 1342 /** 1343 * check for %x or % (null alternate) 1344 * 1345 * @return true if no error 1346 */ clauseAlternateSpec()1347 private boolean clauseAlternateSpec() { 1348 tokenNext(); 1349 // check for termination -- is this really the full list? 1350 if (isTerminator(tokPeek())) 1351 return generateResidueSpecCode(T.o(T.spec_alternate, null)); 1352 switch (getToken().tok) { 1353 case T.times: 1354 case T.string: 1355 case T.integer: 1356 case T.identifier: 1357 case T.opIf: 1358 case T.x: 1359 case T.y: 1360 case T.z: 1361 case T.w: 1362 break; 1363 default: 1364 return error(ERROR_invalidModelSpecification); 1365 } 1366 return generateResidueSpecCode(T.o(T.spec_alternate, theToken.value)); 1367 } 1368 1369 /** 1370 * we allow : and % to have null values 1371 * @param tok 1372 * @return true if terminating 1373 */ isTerminator(int tok)1374 private boolean isTerminator(int tok) { 1375 switch (tok) { 1376 case T.nada: 1377 case T.divide: 1378 case T.opAnd: 1379 case T.opOr: 1380 case T.opNot: 1381 case T.comma: 1382 case T.rightparen: 1383 case T.rightbrace: 1384 return true; 1385 default: 1386 return false; 1387 } 1388 } 1389 1390 1391 /** 1392 * process /1 /1.1 / * or just / 1393 * 1394 * 1395 * @return true if no error 1396 */ clauseModelSpec()1397 private boolean clauseModelSpec() { 1398 getToken(); 1399 switch (tokPeek()) { 1400 case T.times: 1401 getToken(); 1402 return true; 1403 case T.integer: 1404 return generateResidueSpecCode(T.o(T.spec_model, Integer 1405 .valueOf(getToken().intValue))); 1406 case T.decimal: 1407 return generateResidueSpecCode(T.tv(T.spec_model, fixModelSpec(getToken()), theValue)); 1408 case T.comma: 1409 case T.rightbrace: 1410 case T.nada: 1411 // these are necessary to allow for {1 1 1/} or {1/,1/,1} in fractional coordinates 1412 return generateResidueSpecCode(T.o(T.spec_model, Integer 1413 .valueOf(1))); 1414 } 1415 return error(ERROR_invalidModelSpecification); 1416 } 1417 fixModelSpec(T token)1418 private int fixModelSpec(T token) { 1419 int ival = token.intValue; 1420 if (ival == Integer.MAX_VALUE) { 1421 float f = ((Float) theValue).floatValue(); 1422 if (f == (int) f) 1423 ival = ((int) f) * 1000000; 1424 if (ival < 0) 1425 ival = Integer.MAX_VALUE; 1426 } 1427 return ival; 1428 } 1429 1430 clauseAtomSpec()1431 private boolean clauseAtomSpec() { 1432 if (!tokenNextTok(T.per)) 1433 return error(ERROR_invalidAtomSpecification); 1434 if (getToken() == null) 1435 return true; 1436 String atomSpec = ""; 1437 if (theToken.tok == T.integer) { 1438 atomSpec += "" + theToken.intValue; 1439 if (getToken() == null) 1440 return error(ERROR_invalidAtomSpecification); 1441 } 1442 if (theToken.tok == T.times) 1443 return true; 1444 // here we cannot depend upon the atom spec being an identifier 1445 // in other words, not a known Jmol word. As long as the period 1446 // was there, we accept whatever is next 1447 atomSpec += "" + theToken.value; 1448 if (tokPeekIs(T.times)) { 1449 tokenNext(); 1450 // this one is a '*' as a prime, not a wildcard 1451 atomSpec += "'"; 1452 } 1453 return generateResidueSpecCode(T.tv(T.spec_atom, vwr.getJBR() 1454 .lookupSpecialAtomID(atomSpec.toUpperCase()), atomSpec)); 1455 } 1456 1457 //---------------------------------------------------------------------------------------- 1458 //---------------------------------------------------------------------------------------- 1459 //------------ ERROR HANDLING -------------------------------------------------------- 1460 //---------------------------------------------------------------------------------------- 1461 //---------------------------------------------------------------------------------------- 1462 1463 protected String errorMessage; 1464 protected String errorMessageUntranslated; 1465 protected String errorLine; 1466 protected String errorType; 1467 1468 protected final static int ERROR_badArgumentCount = 0; 1469 protected final static int ERROR_badContext = 1; 1470 protected final static int ERROR_commandExpected = 2; 1471 protected final static int ERROR_endOfCommandUnexpected = 4; 1472 protected final static int ERROR_invalidExpressionToken = 9; 1473 protected final static int ERROR_missingEnd = 11; 1474 protected final static int ERROR_tokenExpected = 15; 1475 protected final static int ERROR_tokenUnexpected = 16; 1476 protected final static int ERROR_unrecognizedParameter = 18; 1477 protected final static int ERROR_unrecognizedToken = 19; 1478 1479 private final static int ERROR_coordinateExpected = 3; 1480 private final static int ERROR_endOfExpressionExpected = 5; 1481 private final static int ERROR_identifierOrResidueSpecificationExpected = 6; 1482 private final static int ERROR_invalidAtomSpecification = 7; 1483 private final static int ERROR_invalidChainSpecification = 8; 1484 private final static int ERROR_invalidModelSpecification = 10; 1485 private final static int ERROR_numberExpected = 12; 1486 private final static int ERROR_numberOrVariableNameExpected = 13; 1487 private final static int ERROR_residueSpecificationExpected = 14; 1488 private final static int ERROR_unrecognizedExpressionToken = 17; 1489 errorString(int iError, String value, String more, boolean translated)1490 static String errorString(int iError, String value, String more, 1491 boolean translated) { 1492 boolean doTranslate = false; 1493 if (!translated && (doTranslate = GT.getDoTranslate()) == true) 1494 GT.setDoTranslate(false); 1495 String msg; 1496 switch (iError) { 1497 default: 1498 msg = "Unknown compiler error message number: " + iError; 1499 break; 1500 case ERROR_badArgumentCount: // 0; 1501 msg = GT.$("bad argument count"); // 0 1502 break; 1503 case ERROR_badContext: // 1; 1504 msg = GT.$("invalid context for {0}"); // 1 1505 break; 1506 case ERROR_commandExpected: // 2; 1507 msg = GT.$("command expected"); // 2 1508 break; 1509 case ERROR_coordinateExpected: // 3; 1510 msg = GT.$("{ number number number } expected"); // 3 1511 break; 1512 case ERROR_endOfCommandUnexpected: // 4; 1513 msg = GT.$("unexpected end of script command"); // 4 1514 break; 1515 case ERROR_endOfExpressionExpected: // 5; 1516 msg = GT.$("end of expression expected"); // 5 1517 break; 1518 case ERROR_identifierOrResidueSpecificationExpected: // 6; 1519 msg = GT.$("identifier or residue specification expected"); // 6 1520 break; 1521 case ERROR_invalidAtomSpecification: // 7; 1522 msg = GT.$("invalid atom specification"); // 7 1523 break; 1524 case ERROR_invalidChainSpecification: // 8; 1525 msg = GT.$("invalid chain specification"); // 8 1526 break; 1527 case ERROR_invalidExpressionToken: // 9; 1528 msg = GT.$("invalid expression token: {0}"); // 9 1529 break; 1530 case ERROR_invalidModelSpecification: // 10; 1531 msg = GT.$("invalid model specification"); // 10 1532 break; 1533 case ERROR_missingEnd: // 11; 1534 msg = GT.$("missing END for {0}"); // 11 1535 break; 1536 case ERROR_numberExpected: // 12; 1537 msg = GT.$("number expected"); // 12 1538 break; 1539 case ERROR_numberOrVariableNameExpected: // 13; 1540 msg = GT.$("number or variable name expected"); // 13 1541 break; 1542 case ERROR_residueSpecificationExpected: // 14; 1543 msg = GT.$("residue specification (ALA, AL?, A*) expected"); // 14 1544 break; 1545 case ERROR_tokenExpected: // 15; 1546 msg = GT.$("{0} expected"); // 15 1547 break; 1548 case ERROR_tokenUnexpected: // 16; 1549 msg = GT.$("{0} unexpected"); // 16 1550 break; 1551 case ERROR_unrecognizedExpressionToken: // 17; 1552 msg = GT.$("unrecognized expression token: {0}"); // 17 1553 break; 1554 case ERROR_unrecognizedParameter: // 18; 1555 msg = GT.$("unrecognized {0} parameter"); // 18 1556 break; 1557 case ERROR_unrecognizedToken: // 19; 1558 msg = GT.$("unrecognized token: {0}"); // 19 1559 break; 1560 } 1561 if (msg.indexOf("{0}") < 0) { 1562 if (value != null) 1563 msg += ": " + value; 1564 } else { 1565 msg = PT.rep(msg, "{0}", value); 1566 if (msg.indexOf("{1}") >= 0) 1567 msg = PT.rep(msg, "{1}", more); 1568 else if (more != null) 1569 msg += ": " + more; 1570 } 1571 if (!translated) 1572 GT.setDoTranslate(doTranslate); 1573 return msg; 1574 } 1575 commandExpected()1576 protected boolean commandExpected() { 1577 ichToken = ichCurrentCommand; 1578 return error(ERROR_commandExpected); 1579 } 1580 error(int error)1581 protected boolean error(int error) { 1582 return errorIntStr2(error, null, null); 1583 } 1584 errorStr(int error, String value)1585 protected boolean errorStr(int error, String value) { 1586 return errorIntStr2(error, value, null); 1587 } 1588 errorIntStr2(int iError, String value, String more)1589 protected boolean errorIntStr2(int iError, String value, String more) { 1590 String strError = errorString(iError, value, more, true); 1591 String strUntranslated = (GT.getDoTranslate() ? errorString(iError, value, more, false) : null); 1592 return errorStr2(strError, strUntranslated); 1593 } 1594 isError()1595 private boolean isError() { 1596 return errorMessage != null; 1597 } 1598 errorStr2(String errorMessage, String strUntranslated)1599 protected boolean errorStr2(String errorMessage, String strUntranslated) { 1600 this.errorMessage = errorMessage; 1601 errorMessageUntranslated = strUntranslated; 1602 return false; 1603 } 1604 1605 } 1606