1 /*
   2  * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 options {
  27   JAVA_UNICODE_ESCAPE = true;
  28   STATIC = false;
  29 }
  30 
  31 PARSER_BEGIN(ExpressionParser)
  32 
  33 package com.sun.tools.example.debug.expr;
  34 
  35 import com.sun.jdi.*;
  36 import java.util.Stack;
  37 import java.util.List;
  38 import java.util.ArrayList;
  39 
  40 public class ExpressionParser {    
  41 
  42   Stack stack = new Stack();    
  43   VirtualMachine vm = null;
  44   GetFrame frameGetter = null;
  45   private static GetFrame lastFrameGetter;
  46   private static LValue lastLValue;
  47 
  48   LValue peek() {
  49     return (LValue)stack.peek();
  50   }
  51 
  52   LValue pop() {
  53     return (LValue)stack.pop();
  54   }
  55 
  56   void push(LValue lval) {
  57     stack.push(lval);
  58   }
  59 
  60   public static Value getMassagedValue() throws ParseException {
  61         return lastLValue.getMassagedValue(lastFrameGetter);
  62   }
  63 
  64   public interface GetFrame {
  65         StackFrame get() throws IncompatibleThreadStateException;
  66   }
  67 
  68   public static Value evaluate(String expr, VirtualMachine vm, 
  69                                GetFrame frameGetter) throws ParseException,
  70                                             InvocationException, 
  71                                             InvalidTypeException,
  72                                             ClassNotLoadedException,
  73                                             IncompatibleThreadStateException {
  74         // TODO StringBufferInputStream is deprecated.
  75         java.io.InputStream in = new java.io.StringBufferInputStream(expr);
  76         ExpressionParser parser = new ExpressionParser(in);
  77         parser.vm = vm;
  78         parser.frameGetter = frameGetter;
  79         Value value = null;
  80         parser.Expression();
  81         lastFrameGetter = frameGetter;
  82         lastLValue = parser.pop();
  83         return lastLValue.getValue();
  84   }
  85 
  86   public static void main(String args[]) {
  87     ExpressionParser parser;
  88     System.out.print("Java Expression Parser:  ");
  89     if (args.length == 0) {
  90       System.out.println("Reading from standard input . . .");
  91       parser = new ExpressionParser(System.in);
  92     } else if (args.length == 1) {
  93       System.out.println("Reading from file " + args[0] + " . . .");
  94       try {
  95         parser = new ExpressionParser(new java.io.FileInputStream(args[0]));
  96       } catch (java.io.FileNotFoundException e) {
  97         System.out.println("Java Parser Version 1.0.2:  File " + 
  98                            args[0] + " not found.");
  99         return;
 100       }
 101     } else {
 102       System.out.println("Usage is one of:");
 103       System.out.println("         java ExpressionParser < inputfile");
 104       System.out.println("OR");
 105       System.out.println("         java ExpressionParser inputfile");
 106       return;
 107     }
 108     try {
 109         parser.Expression();
 110         System.out.print("Java Expression Parser:  ");
 111         System.out.println("Java program parsed successfully.");
 112     } catch (ParseException e) {
 113         System.out.print("Java Expression Parser:  ");
 114         System.out.println("Encountered errors during parse.");
 115     }
 116   }
 117 
 118 }
 119 
 120 PARSER_END(ExpressionParser)
 121 
 122 
 123 SKIP : /* WHITE SPACE */
 124 {
 125   " "
 126 | "\t"
 127 | "\n"
 128 | "\r"
 129 | "\f"
 130 }
 131 
 132 SPECIAL_TOKEN : /* COMMENTS */
 133 {
 134   <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
 135 | <FORMAL_COMMENT: "/**" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
 136 | <MULTI_LINE_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
 137 }
 138 
 139 TOKEN : /* RESERVED WORDS AND LITERALS */
 140 {
 141   < ABSTRACT: "abstract" >
 142 | < BOOLEAN: "boolean" >
 143 | < BREAK: "break" >
 144 | < BYTE: "byte" >
 145 | < CASE: "case" >
 146 | < CATCH: "catch" >
 147 | < CHAR: "char" >
 148 | < CLASS: "class" >
 149 | < CONST: "const" >
 150 | < CONTINUE: "continue" >
 151 | < _DEFAULT: "default" >
 152 | < DO: "do" >
 153 | < DOUBLE: "double" >
 154 | < ELSE: "else" >
 155 | < EXTENDS: "extends" >
 156 | < FALSE: "false" >
 157 | < FINAL: "final" >
 158 | < FINALLY: "finally" >
 159 | < FLOAT: "float" >
 160 | < FOR: "for" >
 161 | < GOTO: "goto" >
 162 | < IF: "if" >
 163 | < IMPLEMENTS: "implements" >
 164 | < IMPORT: "import" >
 165 | < INSTANCEOF: "instanceof" >
 166 | < INT: "int" >
 167 | < INTERFACE: "interface" >
 168 | < LONG: "long" >
 169 | < NATIVE: "native" >
 170 | < NEW: "new" >
 171 | < NULL: "null" >
 172 | < PACKAGE: "package">
 173 | < PRIVATE: "private" >
 174 | < PROTECTED: "protected" >
 175 | < PUBLIC: "public" >
 176 | < RETURN: "return" >
 177 | < SHORT: "short" >
 178 | < STATIC: "static" >
 179 | < SUPER: "super" >
 180 | < SWITCH: "switch" >
 181 | < SYNCHRONIZED: "synchronized" >
 182 | < THIS: "this" >
 183 | < THROW: "throw" >
 184 | < THROWS: "throws" >
 185 | < TRANSIENT: "transient" >
 186 | < TRUE: "true" >
 187 | < TRY: "try" >
 188 | < VOID: "void" >
 189 | < VOLATILE: "volatile" >
 190 | < WHILE: "while" >
 191 }
 192 
 193 TOKEN : /* LITERALS */
 194 {
 195   <
 196     INTEGER_LITERAL:
 197         <DECIMAL_LITERAL> (["l","L"])?
 198       | <HEX_LITERAL> (["l","L"])?
 199       | <OCTAL_LITERAL> (["l","L"])?
 200   >
 201 |
 202   < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
 203 |
 204   < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
 205 |
 206   < #OCTAL_LITERAL: "0" (["0"-"7"])* >
 207 |
 208   < FLOATING_POINT_LITERAL:
 209         (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
 210       | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
 211       | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
 212       | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
 213   >
 214 |
 215   < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
 216 |
 217   < CHARACTER_LITERAL:
 218       "'"
 219       (   (~["'","\\","\n","\r"])
 220         | ("\\"
 221             ( ["n","t","b","r","f","\\","'","\""]
 222             | ["0"-"7"] ( ["0"-"7"] )?
 223             | ["0"-"3"] ["0"-"7"] ["0"-"7"]
 224             )
 225           )
 226       )
 227       "'"
 228   >
 229 |
 230   < STRING_LITERAL:
 231       "\""
 232       (   (~["\"","\\","\n","\r"])
 233         | ("\\"
 234             ( ["n","t","b","r","f","\\","'","\""]
 235             | ["0"-"7"] ( ["0"-"7"] )?
 236             | ["0"-"3"] ["0"-"7"] ["0"-"7"]
 237             )
 238           )
 239       )*
 240       "\""
 241   >
 242 }
 243 
 244 TOKEN : /* IDENTIFIERS */
 245 {
 246   < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
 247 |
 248   < #LETTER:
 249       [
 250        "\u0024",
 251        "\u0041"-"\u005a",
 252        "\u005f",
 253        "\u0061"-"\u007a",
 254        "\u00c0"-"\u00d6",
 255        "\u00d8"-"\u00f6",
 256        "\u00f8"-"\u00ff",
 257        "\u0100"-"\u1fff",
 258        "\u3040"-"\u318f",
 259        "\u3300"-"\u337f",
 260        "\u3400"-"\u3d2d",
 261        "\u4e00"-"\u9fff",
 262        "\uf900"-"\ufaff"
 263       ]
 264   >
 265 |
 266   < #DIGIT:
 267       [
 268        "\u0030"-"\u0039",
 269        "\u0660"-"\u0669",
 270        "\u06f0"-"\u06f9",
 271        "\u0966"-"\u096f",
 272        "\u09e6"-"\u09ef",
 273        "\u0a66"-"\u0a6f",
 274        "\u0ae6"-"\u0aef",
 275        "\u0b66"-"\u0b6f",
 276        "\u0be7"-"\u0bef",
 277        "\u0c66"-"\u0c6f",
 278        "\u0ce6"-"\u0cef",
 279        "\u0d66"-"\u0d6f",
 280        "\u0e50"-"\u0e59",
 281        "\u0ed0"-"\u0ed9",
 282        "\u1040"-"\u1049"
 283       ]
 284   >
 285 }
 286 
 287 TOKEN : /* SEPARATORS */
 288 {
 289   < LPAREN: "(" >
 290 | < RPAREN: ")" >
 291 | < LBRACE: "{" >
 292 | < RBRACE: "}" >
 293 | < LBRACKET: "[" >
 294 | < RBRACKET: "]" >
 295 | < SEMICOLON: ";" >
 296 | < COMMA: "," >
 297 | < DOT: "." >
 298 }
 299 
 300 TOKEN : /* OPERATORS */
 301 {
 302   < ASSIGN: "=" >
 303 | < GT: ">" >
 304 | < LT: "<" >
 305 | < BANG: "!" >
 306 | < TILDE: "~" >
 307 | < HOOK: "?" >
 308 | < COLON: ":" >
 309 | < EQ: "==" >
 310 | < LE: "<=" >
 311 | < GE: ">=" >
 312 | < NE: "!=" >
 313 | < SC_OR: "||" >
 314 | < SC_AND: "&&" >
 315 | < INCR: "++" >
 316 | < DECR: "--" >
 317 | < PLUS: "+" >
 318 | < MINUS: "-" >
 319 | < STAR: "*" >
 320 | < SLASH: "/" >
 321 | < BIT_AND: "&" >
 322 | < BIT_OR: "|" >
 323 | < XOR: "^" >
 324 | < REM: "%" >
 325 | < LSHIFT: "<<" >
 326 | < RSIGNEDSHIFT: ">>" >
 327 | < RUNSIGNEDSHIFT: ">>>" >
 328 | < PLUSASSIGN: "+=" >
 329 | < MINUSASSIGN: "-=" >
 330 | < STARASSIGN: "*=" >
 331 | < SLASHASSIGN: "/=" >
 332 | < ANDASSIGN: "&=" >
 333 | < ORASSIGN: "|=" >
 334 | < XORASSIGN: "^=" >
 335 | < REMASSIGN: "%=" >
 336 | < LSHIFTASSIGN: "<<=" >
 337 | < RSIGNEDSHIFTASSIGN: ">>=" >
 338 | < RUNSIGNEDSHIFTASSIGN: ">>>=" >
 339 }
 340 
 341 
 342 /*****************************************
 343  * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
 344  *****************************************/
 345 
 346 /*
 347  * Type, name and expression syntax follows.
 348  */
 349 
 350 void Type() :
 351 {}
 352 {
 353   ( PrimitiveType() | Name() ) ( "[" "]" )*
 354 }
 355 
 356 void PrimitiveType() :
 357 {}
 358 {
 359   "boolean"
 360 |
 361   "char"
 362 |
 363   "byte"
 364 |
 365   "short"
 366 |
 367   "int"
 368 |
 369   "long"
 370 |
 371   "float"
 372 |
 373   "double"
 374 }
 375 
 376 
 377 String Name() :
 378 {StringBuffer sb = new StringBuffer();}
 379 {
 380   <IDENTIFIER> { sb.append(token); }
 381   ( LOOKAHEAD(2) "." <IDENTIFIER> { sb.append('.'); sb.append(token); }
 382   )*
 383         { return sb.toString(); }
 384 }
 385 
 386 void NameList() :
 387 {}
 388 {
 389   Name()
 390   ( "," Name()
 391   )*
 392 }
 393 
 394 
 395 /*
 396  * Expression syntax follows.
 397  */
 398 
 399 void Expression() :
 400 {}
 401 {
 402   LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
 403   Assignment()
 404 |
 405   ConditionalExpression()
 406 }
 407 
 408 void Assignment() :
 409 {}
 410 {
 411   PrimaryExpression() AssignmentOperator() Expression()
 412         { LValue exprVal = pop(); pop().setValue(exprVal); push(exprVal);}
 413 }
 414 
 415 void AssignmentOperator() :
 416 {}
 417 {
 418   "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|="
 419 }
 420 
 421 void ConditionalExpression() :
 422 {}
 423 {
 424   ConditionalOrExpression() 
 425         [ "?" Expression() ":" ConditionalExpression() 
 426                 { LValue falseBranch = pop(); LValue trueBranch = pop(); 
 427                   Value cond = pop().interiorGetValue();
 428                   if (cond instanceof BooleanValue) {
 429                         push(((BooleanValue)cond).booleanValue()? 
 430                                         trueBranch : falseBranch);
 431                   } else {
 432                         throw new ParseException("Condition must be boolean");
 433                   }
 434                 }
 435         ]
 436 }
 437 
 438 void ConditionalOrExpression() :
 439 {}
 440 {
 441   ConditionalAndExpression() 
 442         ( "||" ConditionalAndExpression() 
 443                         { throw new ParseException("operation not yet supported"); }
 444         )*
 445 }
 446 
 447 void ConditionalAndExpression() :
 448 {}
 449 {
 450   InclusiveOrExpression() 
 451         ( "&&" InclusiveOrExpression() 
 452                         { throw new ParseException("operation not yet supported"); }
 453         )*
 454 }
 455 
 456 void InclusiveOrExpression() :
 457 {}
 458 {
 459   ExclusiveOrExpression() 
 460         ( "|" ExclusiveOrExpression() 
 461                         { throw new ParseException("operation not yet supported"); }
 462         )*
 463 }
 464 
 465 void ExclusiveOrExpression() :
 466 {}
 467 {
 468   AndExpression() 
 469         ( "^" AndExpression() 
 470                         { throw new ParseException("operation not yet supported"); }
 471         )*
 472 }
 473 
 474 void AndExpression() :
 475 {}
 476 {
 477   EqualityExpression() 
 478         ( "&" EqualityExpression() 
 479                         { throw new ParseException("operation not yet supported"); }
 480         )*
 481 }
 482 
 483 void EqualityExpression() :
 484 {Token tok;}
 485 {
 486   InstanceOfExpression() 
 487         ( ( tok = "==" | tok = "!=" ) InstanceOfExpression() 
 488                 { LValue left = pop(); 
 489                   push( LValue.booleanOperation(vm, tok, pop(), left) ); }
 490         )*
 491 }
 492 
 493 void InstanceOfExpression() :
 494 {}
 495 {
 496   RelationalExpression() 
 497         [ "instanceof" Type() 
 498                         { throw new ParseException("operation not yet supported"); }
 499         ]
 500 }
 501 
 502 void RelationalExpression() :
 503 {Token tok;}
 504 {
 505   ShiftExpression() 
 506         ( ( tok = "<" | tok = ">" | tok = "<=" | tok = ">=" ) ShiftExpression()
 507                 { LValue left = pop(); 
 508                   push( LValue.booleanOperation(vm, tok, pop(), left) ); }
 509          )*
 510 }
 511 
 512 void ShiftExpression() :
 513 {}
 514 {
 515   AdditiveExpression() 
 516         ( ( "<<" | ">>" | ">>>" ) AdditiveExpression() 
 517                         { throw new ParseException("operation not yet supported"); }
 518         )*
 519 }
 520 
 521 void AdditiveExpression() :
 522 {Token tok;}
 523 {
 524   MultiplicativeExpression() 
 525         ( ( tok = "+" | tok = "-" ) MultiplicativeExpression() 
 526                 { LValue left = pop(); 
 527                   push( LValue.operation(vm, tok, pop(), left, frameGetter) ); }
 528         )*
 529 }
 530 
 531 void MultiplicativeExpression() :
 532 {Token tok;}
 533 {
 534   UnaryExpression() 
 535         ( ( tok = "*" | tok = "/" | tok = "%" ) UnaryExpression()
 536                 { LValue left = pop(); 
 537                   push( LValue.operation(vm, tok, pop(), left, frameGetter) ); }
 538         )*
 539 }
 540 
 541 void UnaryExpression() :
 542 {Token tok;}
 543 {
 544   ( tok = "+" | tok = "-" ) UnaryExpression()
 545                 { push( LValue.operation(vm, tok, pop(), frameGetter) ); }
 546 |
 547   PreIncrementExpression()
 548 |
 549   PreDecrementExpression()
 550 |
 551   UnaryExpressionNotPlusMinus()
 552 }
 553 
 554 void PreIncrementExpression() :
 555 {}
 556 {
 557   "++" PrimaryExpression()
 558                         { throw new ParseException("operation not yet supported"); }
 559 }
 560 
 561 void PreDecrementExpression() :
 562 {}
 563 {
 564   "--" PrimaryExpression()
 565                         { throw new ParseException("operation not yet supported"); }
 566 }
 567 
 568 void UnaryExpressionNotPlusMinus() :
 569 {Token tok;}
 570 {
 571   ( tok = "~" | tok = "!" ) UnaryExpression()
 572                 { push( LValue.operation(vm, tok, pop(), frameGetter) ); }
 573 |
 574   LOOKAHEAD( CastLookahead() )
 575   CastExpression()
 576 |
 577   PostfixExpression()
 578 }
 579 
 580 // This production is to determine lookahead only.  The LOOKAHEAD specifications
 581 // below are not used, but they are there just to indicate that we know about
 582 // this.
 583 void CastLookahead() :
 584 {}
 585 {
 586   LOOKAHEAD(2)
 587   "(" PrimitiveType()
 588 |
 589   LOOKAHEAD("(" Name() "[")
 590   "(" Name() "[" "]"
 591 |
 592   "(" Name() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() )
 593 }
 594 
 595 void PostfixExpression() :
 596 {}
 597 {
 598   PrimaryExpression() 
 599         [ "++" | "--" 
 600                         { throw new ParseException("operation not yet supported"); }
 601         ]
 602 }
 603 
 604 void CastExpression() :
 605 {}
 606 {
 607   LOOKAHEAD(2)
 608   "(" PrimitiveType() ( "[" "]" )* ")" UnaryExpression()
 609 |
 610   "(" Name() ( "[" "]" )* ")" UnaryExpressionNotPlusMinus()
 611 }
 612 
 613 void PrimaryExpression() :
 614 {}
 615 {
 616   PrimaryPrefix() ( PrimarySuffix() )*
 617 }
 618 
 619 void PrimaryPrefix() :
 620 {String name;}
 621 {
 622   Literal()
 623 |
 624   name = Name()
 625                         { push(LValue.makeName(vm, frameGetter, name)); }
 626 |
 627   "this"
 628                         { push(LValue.makeThisObject(vm, frameGetter, token)); }
 629 |
 630   "super" "." <IDENTIFIER>
 631                         { throw new ParseException("operation not yet supported"); }
 632 |
 633   "(" Expression() ")"
 634 |
 635   AllocationExpression()
 636 }
 637 
 638 void PrimarySuffix() :
 639 {List argList;}
 640 {
 641   "[" Expression() "]"  
 642                         { LValue index = pop();
 643                           push(pop().arrayElementLValue(index)); }
 644 |
 645   "." <IDENTIFIER>
 646                         { push(pop().memberLValue(frameGetter, token.image)); }
 647 |
 648   argList = Arguments()
 649                         { peek().invokeWith(argList); }
 650 }
 651 
 652 void Literal() :
 653 {}
 654 {
 655   <INTEGER_LITERAL>
 656                         { push(LValue.makeInteger(vm, token)); }
 657 |
 658   <FLOATING_POINT_LITERAL>
 659                         { push(LValue.makeFloat(vm, token)); }
 660 |
 661   <CHARACTER_LITERAL>
 662                         { push(LValue.makeCharacter(vm, token)); }
 663 |
 664   <STRING_LITERAL>
 665                         { push(LValue.makeString(vm, token)); }
 666 |
 667   BooleanLiteral()
 668                         { push(LValue.makeBoolean(vm, token)); }
 669 |
 670   NullLiteral()
 671                         { push(LValue.makeNull(vm, token)); }
 672 }
 673 
 674 void BooleanLiteral() :
 675 {}
 676 {
 677   "true" 
 678 |
 679   "false"
 680 }
 681 
 682 void NullLiteral() :
 683 {}
 684 {
 685   "null"
 686 }
 687 
 688 List Arguments() :
 689 {List argList = new ArrayList();}
 690 {
 691   "(" [ ArgumentList(argList) ] ")"
 692   { return argList; }
 693 }
 694 
 695 void ArgumentList(List argList) :
 696 {}
 697 {
 698   Expression() {argList.add(pop().interiorGetValue());}
 699   ( "," Expression() {argList.add(pop().interiorGetValue());} )*
 700 }
 701 
 702 void AllocationExpression() :
 703 {List argList; String className;}
 704 {
 705   LOOKAHEAD(2)
 706   "new" PrimitiveType() ArrayDimensions()
 707 |
 708   "new" className = Name() ( argList = Arguments() 
 709                         { push(LValue.makeNewObject(vm, frameGetter, className, argList)); }
 710                            | ArrayDimensions() 
 711                         { throw new ParseException("operation not yet supported"); }
 712                            )
 713 }
 714 
 715 /*
 716  * The second LOOKAHEAD specification below is to parse to PrimarySuffix
 717  * if there is an expression between the "[...]".
 718  */
 719 void ArrayDimensions() :
 720 {}
 721 {
 722   ( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )*
 723 }
 724