blob: ffe12e35d7f1acfe2332c1435795fa1c30262e50 [file] [log] [blame]
/*
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
options {
JAVA_UNICODE_ESCAPE = true;
STATIC = false;
}
PARSER_BEGIN(ExpressionParser)
package com.sun.tools.example.debug.expr;
import com.sun.jdi.*;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
public class ExpressionParser {
Stack stack = new Stack();
VirtualMachine vm = null;
GetFrame frameGetter = null;
private static GetFrame lastFrameGetter;
private static LValue lastLValue;
LValue peek() {
return (LValue)stack.peek();
}
LValue pop() {
return (LValue)stack.pop();
}
void push(LValue lval) {
stack.push(lval);
}
public static Value getMassagedValue() throws ParseException {
return lastLValue.getMassagedValue(lastFrameGetter);
}
public interface GetFrame {
StackFrame get() throws IncompatibleThreadStateException;
}
public static Value evaluate(String expr, VirtualMachine vm,
GetFrame frameGetter) throws ParseException,
InvocationException,
InvalidTypeException,
ClassNotLoadedException,
IncompatibleThreadStateException {
// TODO StringBufferInputStream is deprecated.
java.io.InputStream in = new java.io.StringBufferInputStream(expr);
ExpressionParser parser = new ExpressionParser(in);
parser.vm = vm;
parser.frameGetter = frameGetter;
Value value = null;
parser.Expression();
lastFrameGetter = frameGetter;
lastLValue = parser.pop();
return lastLValue.getValue();
}
public static void main(String args[]) {
ExpressionParser parser;
System.out.print("Java Expression Parser: ");
if (args.length == 0) {
System.out.println("Reading from standard input . . .");
parser = new ExpressionParser(System.in);
} else if (args.length == 1) {
System.out.println("Reading from file " + args[0] + " . . .");
try {
parser = new ExpressionParser(new java.io.FileInputStream(args[0]));
} catch (java.io.FileNotFoundException e) {
System.out.println("Java Parser Version 1.0.2: File " +
args[0] + " not found.");
return;
}
} else {
System.out.println("Usage is one of:");
System.out.println(" java ExpressionParser < inputfile");
System.out.println("OR");
System.out.println(" java ExpressionParser inputfile");
return;
}
try {
parser.Expression();
System.out.print("Java Expression Parser: ");
System.out.println("Java program parsed successfully.");
} catch (ParseException e) {
System.out.print("Java Expression Parser: ");
System.out.println("Encountered errors during parse.");
}
}
}
PARSER_END(ExpressionParser)
SKIP : /* WHITE SPACE */
{
" "
| "\t"
| "\n"
| "\r"
| "\f"
}
SPECIAL_TOKEN : /* COMMENTS */
{
<SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
| <FORMAL_COMMENT: "/**" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
| <MULTI_LINE_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
}
TOKEN : /* RESERVED WORDS AND LITERALS */
{
< ABSTRACT: "abstract" >
| < BOOLEAN: "boolean" >
| < BREAK: "break" >
| < BYTE: "byte" >
| < CASE: "case" >
| < CATCH: "catch" >
| < CHAR: "char" >
| < CLASS: "class" >
| < CONST: "const" >
| < CONTINUE: "continue" >
| < _DEFAULT: "default" >
| < DO: "do" >
| < DOUBLE: "double" >
| < ELSE: "else" >
| < EXTENDS: "extends" >
| < FALSE: "false" >
| < FINAL: "final" >
| < FINALLY: "finally" >
| < FLOAT: "float" >
| < FOR: "for" >
| < GOTO: "goto" >
| < IF: "if" >
| < IMPLEMENTS: "implements" >
| < IMPORT: "import" >
| < INSTANCEOF: "instanceof" >
| < INT: "int" >
| < INTERFACE: "interface" >
| < LONG: "long" >
| < NATIVE: "native" >
| < NEW: "new" >
| < NULL: "null" >
| < PACKAGE: "package">
| < PRIVATE: "private" >
| < PROTECTED: "protected" >
| < PUBLIC: "public" >
| < RETURN: "return" >
| < SHORT: "short" >
| < STATIC: "static" >
| < SUPER: "super" >
| < SWITCH: "switch" >
| < SYNCHRONIZED: "synchronized" >
| < THIS: "this" >
| < THROW: "throw" >
| < THROWS: "throws" >
| < TRANSIENT: "transient" >
| < TRUE: "true" >
| < TRY: "try" >
| < VOID: "void" >
| < VOLATILE: "volatile" >
| < WHILE: "while" >
}
TOKEN : /* LITERALS */
{
<
INTEGER_LITERAL:
<DECIMAL_LITERAL> (["l","L"])?
| <HEX_LITERAL> (["l","L"])?
| <OCTAL_LITERAL> (["l","L"])?
>
|
< #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
|
< #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
|
< #OCTAL_LITERAL: "0" (["0"-"7"])* >
|
< FLOATING_POINT_LITERAL:
(["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
| "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
| (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
| (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
>
|
< #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
|
< CHARACTER_LITERAL:
"'"
( (~["'","\\","\n","\r"])
| ("\\"
( ["n","t","b","r","f","\\","'","\""]
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
)
)
"'"
>
|
< STRING_LITERAL:
"\""
( (~["\"","\\","\n","\r"])
| ("\\"
( ["n","t","b","r","f","\\","'","\""]
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
)
)*
"\""
>
}
TOKEN : /* IDENTIFIERS */
{
< IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
|
< #LETTER:
[
"\u0024",
"\u0041"-"\u005a",
"\u005f",
"\u0061"-"\u007a",
"\u00c0"-"\u00d6",
"\u00d8"-"\u00f6",
"\u00f8"-"\u00ff",
"\u0100"-"\u1fff",
"\u3040"-"\u318f",
"\u3300"-"\u337f",
"\u3400"-"\u3d2d",
"\u4e00"-"\u9fff",
"\uf900"-"\ufaff"
]
>
|
< #DIGIT:
[
"\u0030"-"\u0039",
"\u0660"-"\u0669",
"\u06f0"-"\u06f9",
"\u0966"-"\u096f",
"\u09e6"-"\u09ef",
"\u0a66"-"\u0a6f",
"\u0ae6"-"\u0aef",
"\u0b66"-"\u0b6f",
"\u0be7"-"\u0bef",
"\u0c66"-"\u0c6f",
"\u0ce6"-"\u0cef",
"\u0d66"-"\u0d6f",
"\u0e50"-"\u0e59",
"\u0ed0"-"\u0ed9",
"\u1040"-"\u1049"
]
>
}
TOKEN : /* SEPARATORS */
{
< LPAREN: "(" >
| < RPAREN: ")" >
| < LBRACE: "{" >
| < RBRACE: "}" >
| < LBRACKET: "[" >
| < RBRACKET: "]" >
| < SEMICOLON: ";" >
| < COMMA: "," >
| < DOT: "." >
}
TOKEN : /* OPERATORS */
{
< ASSIGN: "=" >
| < GT: ">" >
| < LT: "<" >
| < BANG: "!" >
| < TILDE: "~" >
| < HOOK: "?" >
| < COLON: ":" >
| < EQ: "==" >
| < LE: "<=" >
| < GE: ">=" >
| < NE: "!=" >
| < SC_OR: "||" >
| < SC_AND: "&&" >
| < INCR: "++" >
| < DECR: "--" >
| < PLUS: "+" >
| < MINUS: "-" >
| < STAR: "*" >
| < SLASH: "/" >
| < BIT_AND: "&" >
| < BIT_OR: "|" >
| < XOR: "^" >
| < REM: "%" >
| < LSHIFT: "<<" >
| < RSIGNEDSHIFT: ">>" >
| < RUNSIGNEDSHIFT: ">>>" >
| < PLUSASSIGN: "+=" >
| < MINUSASSIGN: "-=" >
| < STARASSIGN: "*=" >
| < SLASHASSIGN: "/=" >
| < ANDASSIGN: "&=" >
| < ORASSIGN: "|=" >
| < XORASSIGN: "^=" >
| < REMASSIGN: "%=" >
| < LSHIFTASSIGN: "<<=" >
| < RSIGNEDSHIFTASSIGN: ">>=" >
| < RUNSIGNEDSHIFTASSIGN: ">>>=" >
}
/*****************************************
* THE JAVA LANGUAGE GRAMMAR STARTS HERE *
*****************************************/
/*
* Type, name and expression syntax follows.
*/
void Type() :
{}
{
( PrimitiveType() | Name() ) ( "[" "]" )*
}
void PrimitiveType() :
{}
{
"boolean"
|
"char"
|
"byte"
|
"short"
|
"int"
|
"long"
|
"float"
|
"double"
}
String Name() :
{StringBuffer sb = new StringBuffer();}
{
<IDENTIFIER> { sb.append(token); }
( LOOKAHEAD(2) "." <IDENTIFIER> { sb.append('.'); sb.append(token); }
)*
{ return sb.toString(); }
}
void NameList() :
{}
{
Name()
( "," Name()
)*
}
/*
* Expression syntax follows.
*/
void Expression() :
{}
{
LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
Assignment()
|
ConditionalExpression()
}
void Assignment() :
{}
{
PrimaryExpression() AssignmentOperator() Expression()
{ LValue exprVal = pop(); pop().setValue(exprVal); push(exprVal);}
}
void AssignmentOperator() :
{}
{
"=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|="
}
void ConditionalExpression() :
{}
{
ConditionalOrExpression()
[ "?" Expression() ":" ConditionalExpression()
{ LValue falseBranch = pop(); LValue trueBranch = pop();
Value cond = pop().interiorGetValue();
if (cond instanceof BooleanValue) {
push(((BooleanValue)cond).booleanValue()?
trueBranch : falseBranch);
} else {
throw new ParseException("Condition must be boolean");
}
}
]
}
void ConditionalOrExpression() :
{}
{
ConditionalAndExpression()
( "||" ConditionalAndExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void ConditionalAndExpression() :
{}
{
InclusiveOrExpression()
( "&&" InclusiveOrExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void InclusiveOrExpression() :
{}
{
ExclusiveOrExpression()
( "|" ExclusiveOrExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void ExclusiveOrExpression() :
{}
{
AndExpression()
( "^" AndExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void AndExpression() :
{}
{
EqualityExpression()
( "&" EqualityExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void EqualityExpression() :
{Token tok;}
{
InstanceOfExpression()
( ( tok = "==" | tok = "!=" ) InstanceOfExpression()
{ LValue left = pop();
push( LValue.booleanOperation(vm, tok, pop(), left) ); }
)*
}
void InstanceOfExpression() :
{}
{
RelationalExpression()
[ "instanceof" Type()
{ throw new ParseException("operation not yet supported"); }
]
}
void RelationalExpression() :
{Token tok;}
{
ShiftExpression()
( ( tok = "<" | tok = ">" | tok = "<=" | tok = ">=" ) ShiftExpression()
{ LValue left = pop();
push( LValue.booleanOperation(vm, tok, pop(), left) ); }
)*
}
void ShiftExpression() :
{}
{
AdditiveExpression()
( ( "<<" | ">>" | ">>>" ) AdditiveExpression()
{ throw new ParseException("operation not yet supported"); }
)*
}
void AdditiveExpression() :
{Token tok;}
{
MultiplicativeExpression()
( ( tok = "+" | tok = "-" ) MultiplicativeExpression()
{ LValue left = pop();
push( LValue.operation(vm, tok, pop(), left, frameGetter) ); }
)*
}
void MultiplicativeExpression() :
{Token tok;}
{
UnaryExpression()
( ( tok = "*" | tok = "/" | tok = "%" ) UnaryExpression()
{ LValue left = pop();
push( LValue.operation(vm, tok, pop(), left, frameGetter) ); }
)*
}
void UnaryExpression() :
{}
{
( "+" | "-" ) UnaryExpression()
{ throw new ParseException("operation not yet supported"); }
|
PreIncrementExpression()
|
PreDecrementExpression()
|
UnaryExpressionNotPlusMinus()
}
void PreIncrementExpression() :
{}
{
"++" PrimaryExpression()
{ throw new ParseException("operation not yet supported"); }
}
void PreDecrementExpression() :
{}
{
"--" PrimaryExpression()
{ throw new ParseException("operation not yet supported"); }
}
void UnaryExpressionNotPlusMinus() :
{}
{
( "~" | "!" ) UnaryExpression()
{ throw new ParseException("operation not yet supported"); }
|
LOOKAHEAD( CastLookahead() )
CastExpression()
|
PostfixExpression()
}
// This production is to determine lookahead only. The LOOKAHEAD specifications
// below are not used, but they are there just to indicate that we know about
// this.
void CastLookahead() :
{}
{
LOOKAHEAD(2)
"(" PrimitiveType()
|
LOOKAHEAD("(" Name() "[")
"(" Name() "[" "]"
|
"(" Name() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() )
}
void PostfixExpression() :
{}
{
PrimaryExpression()
[ "++" | "--"
{ throw new ParseException("operation not yet supported"); }
]
}
void CastExpression() :
{}
{
LOOKAHEAD(2)
"(" PrimitiveType() ( "[" "]" )* ")" UnaryExpression()
|
"(" Name() ( "[" "]" )* ")" UnaryExpressionNotPlusMinus()
}
void PrimaryExpression() :
{}
{
PrimaryPrefix() ( PrimarySuffix() )*
}
void PrimaryPrefix() :
{String name;}
{
Literal()
|
name = Name()
{ push(LValue.makeName(vm, frameGetter, name)); }
|
"this"
{ push(LValue.makeThisObject(vm, frameGetter, token)); }
|
"super" "." <IDENTIFIER>
{ throw new ParseException("operation not yet supported"); }
|
"(" Expression() ")"
|
AllocationExpression()
}
void PrimarySuffix() :
{List argList;}
{
"[" Expression() "]"
{ LValue index = pop();
push(pop().arrayElementLValue(index)); }
|
"." <IDENTIFIER>
{ push(pop().memberLValue(frameGetter, token.image)); }
|
argList = Arguments()
{ peek().invokeWith(argList); }
}
void Literal() :
{}
{
<INTEGER_LITERAL>
{ push(LValue.makeInteger(vm, token)); }
|
<FLOATING_POINT_LITERAL>
{ push(LValue.makeFloat(vm, token)); }
|
<CHARACTER_LITERAL>
{ push(LValue.makeCharacter(vm, token)); }
|
<STRING_LITERAL>
{ push(LValue.makeString(vm, token)); }
|
BooleanLiteral()
{ push(LValue.makeBoolean(vm, token)); }
|
NullLiteral()
{ push(LValue.makeNull(vm, token)); }
}
void BooleanLiteral() :
{}
{
"true"
|
"false"
}
void NullLiteral() :
{}
{
"null"
}
List Arguments() :
{List argList = new ArrayList();}
{
"(" [ ArgumentList(argList) ] ")"
{ return argList; }
}
void ArgumentList(List argList) :
{}
{
Expression() {argList.add(pop().interiorGetValue());}
( "," Expression() {argList.add(pop().interiorGetValue());} )*
}
void AllocationExpression() :
{List argList; String className;}
{
LOOKAHEAD(2)
"new" PrimitiveType() ArrayDimensions()
|
"new" className = Name() ( argList = Arguments()
{ push(LValue.makeNewObject(vm, frameGetter, className, argList)); }
| ArrayDimensions()
{ throw new ParseException("operation not yet supported"); }
)
}
/*
* The second LOOKAHEAD specification below is to parse to PrimarySuffix
* if there is an expression between the "[...]".
*/
void ArrayDimensions() :
{}
{
( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )*
}