📄 parser.jj
字号:
options { LOOKAHEAD = 1; CHOICE_AMBIGUITY_CHECK = 2; OTHER_AMBIGUITY_CHECK = 1; STATIC = false; // default is true DEBUG_PARSER = false; //default is false DEBUG_LOOKAHEAD = false; DEBUG_TOKEN_MANAGER = false; ERROR_REPORTING = true; // default is true (setting to false is supposed to improve performance) JAVA_UNICODE_ESCAPE = false; // default is false UNICODE_INPUT = false; IGNORE_CASE = false; USER_TOKEN_MANAGER = false; USER_CHAR_STREAM = false; BUILD_PARSER = true; BUILD_TOKEN_MANAGER = true; SANITY_CHECK = true; FORCE_LA_CHECK = false; CACHE_TOKENS = true; //default is false (setting to true improves performance) OPTIMIZE_TOKEN_MANAGER = true; //default is false (setting to true improves performance)}/* * WebWork, Web Application Framework * * Distributable under Apache license. * See terms of license at opensource.org */PARSER_BEGIN(Parser)package webwork.expr;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import webwork.util.ValueStack;/** * The WebWork Expression language Parser and Interpreter. * * @author Maurice C. Parker (maurice@vineyardenterprise.com) * @version $Revision: 1.21 $ */ public final class Parser{ // Attributes ---------------------------------------------------- private ValueStack valueStack; private int nestDepth = 0; protected static Log log = LogFactory.getLog(Parser.class); // Public -------------------------------------------------------- /** * Set the value stack */ public void setValueStack(ValueStack valueStack) { this.valueStack = valueStack; } // Private ------------------------------------------------------- /** * This method moves the current token to the next matching * paren. This is necessary when you want to end an evaluation * inside a nested "||" statement early. * */ private void consume_remaining_or_tokens() { Token token; int nesting = 1; while (true) { token = getToken(1); if (token.kind == LPAREN) nesting++; if (token.kind == RPAREN) { nesting--; if (nesting == 0) break; } token = getNextToken(); } } /** * This method moves the current token to the next matching * paren. This is necessary when you want to end an evaluation * inside a nested "&&" statement early. * */ private void consume_remaining_and_tokens() { Token token; int nesting = 1; while (true) { token = getToken(1); if (token.kind == OR) break; if (token.kind == LPAREN) nesting++; if (token.kind == RPAREN) { nesting--; if (nesting == 0) break; } token = getNextToken(); } } /** * determine true or false by comparing the comparison result * with the operator. * * @param comp the comparison result * @param operatr the operator * @return the boolean result * */ private boolean resolve(int comp, Token operatr) { //log.debug( "comp: " + comp + ", operatr: " + operatr); if ( comp == 0 ) { switch (operatr.kind) { case EQ: case GE: case LE: return true; default: return false; } } if ( comp > 0 ) { switch (operatr.kind) { case GT: case GE: case NE: return true; default: return false; } } switch (operatr.kind) { case LT: case LE: case NE: return true; } return false; }}PARSER_END(Parser)///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////SKIP :{ " "| "\t"| "\n"| "\r"}TOKEN : /* id */{< ID:( <STRING_LITERAL> | ["a"-"z","A"-"Z","0"-"9","_","-",":","@","$",".","/","{","["] ( ["a"-"z","A"-"Z","0"-"9","_","-",":","'","@","$",".","/","{","}","[","]"] )* ( "(" ( ( ["a"-"z","A"-"Z","0"-"9"," ","_","-",":","'","@","$",",",".","/","{","}","[","]"] )* | <STRING_LITERAL> ) ")" )* ( ["a"-"z","A"-"Z","0"-"9","_","-",":","@","$",".","/","{","}","[","]"] )* ( "(" ( ( ["a"-"z","A"-"Z","0"-"9"," ","_","-",":","'","@","$",",",".","/","{","}","[","]"] )* | <STRING_LITERAL> ) ")" )*) >}TOKEN : /* string literal */{< STRING_LITERAL: "'" ( ~["'"] )* "'" >}TOKEN : /* parens */{ < LPAREN: "(" > | < RPAREN: ")" >}TOKEN : /* boolean operators */{ < EQ: "==" > | < NE: "!=" > | < GT: ">" > | < GE: ">=" > | < LT: "<" > | < LE: "<=" > | < AND: "&&" > | < OR: "||" >}boolean test() : // would be logical_or_expression{ boolean answer;}{ answer=logical_and_expression() { if ( answer == true ) { if ( nestDepth > 0 ) consume_remaining_or_tokens(); return true; } } ( "||" answer=logical_and_expression() { if ( answer == true ) { if ( nestDepth > 0 ) consume_remaining_or_tokens(); return true; } } )* { return false; }}boolean logical_and_expression() :{ boolean answer;}{ answer=comparative_expression() { if ( answer == false ) { if ( nestDepth > 0 ) consume_remaining_and_tokens(); return false; } } ( "&&" answer=comparative_expression() { if ( answer == false ) { if ( nestDepth > 0 ) consume_remaining_and_tokens(); return false; } } )* { return true; }}boolean comparative_expression() :{ Token token; Object operand1; Object operand2; boolean answer = false;}{ ( { nestDepth++; } <LPAREN> answer=test() <RPAREN> { nestDepth--; } | // Null test "!" operand1=findValue() { if ( operand1 == null ) return true; else return false; } | ( // Not null test operand1=findValue() { if ( operand1 != null ) answer = true; else answer = false; } // Normal comparison ( ( token=<EQ> | token=<NE> | token=<GT> | token=<GE> | token=<LT> | token=<LE> ) operand2 = findValue() { // We resolve nulls by hand if ( operand1 == null || operand2 == null ) { int comp = -1; // less than if ( operand1 == null && operand2 == null ) // equal to { comp = 0; } else if ( operand2 == null ) // greater than { comp = 1; } return resolve(comp, token); } if ( operand1 instanceof Number && operand2 instanceof Number ) { double number1 = ((Number)operand1).doubleValue(); double number2 = ((Number)operand2).doubleValue(); int comp = -1; // less than if ( number1 > number2 ) { comp = 1; // greater than } else if ( number1 == number2 ) { long longBits1 = Double.doubleToLongBits(number1); long longBits2 = Double.doubleToLongBits(number2); if ( longBits1 > longBits2 ) { comp = 1; } else if ( longBits1 == longBits2 ) { comp = 0; } } return resolve(comp, token); } // If operands are of the same type, do a direct comparison if ( operand1.getClass().equals(operand2.getClass()) ) { if ( operand1 instanceof Comparable ) { int comp = ((Comparable)operand1).compareTo(operand2); return resolve(comp, token); } } // If the operands aren't the same type or aren't comparible, then // convert them to strings and do a comparison // Mo: I think that this could lead to some difficult to predict or unpredictable behavior operand1 = operand1.toString(); operand2 = operand2.toString(); int comp = ((Comparable)operand1).compareTo(operand2); return resolve(comp, token); } )? ) ) { return answer; }}Object findValue() :{ Token token;}{ /* Constants */ token=<ID> { return valueStack.findValue(token.image); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -