ExpressionParseTreepublic class ExpressionParseTree extends Object Represents a parsed expression. |
Fields Summary |
---|
private LinkedList | nodeStackContains the current set of completed nodes. This is a workspace for the
parser. | private LinkedList | oppStackContains operator nodes that don't yet have values. This is a workspace
for the parser. | private Node | rootThe root node after the expression has been parsed. | private SSIMediator | ssiMediatorThe SSIMediator to use when evaluating the expressions. | private static final int | PRECEDENCE_NOT | private static final int | PRECEDENCE_COMPARE | private static final int | PRECEDENCE_LOGICAL |
Constructors Summary |
---|
public ExpressionParseTree(String expr, SSIMediator ssiMediator)Creates a new parse tree for the specified expression.
this.ssiMediator = ssiMediator;
parseExpression(expr);
|
Methods Summary |
---|
public boolean | evaluateTree()Evaluates the tree and returns true or false. The specified SSIMediator
is used to resolve variable references.
return root.evaluate();
| private void | parseExpression(java.lang.String expr)Parses the specified expression into a tree of parse nodes.
StringNode currStringNode = null;
// We cheat a little and start an artificial
// group right away. It makes finishing easier.
pushOpp(null);
ExpressionTokenizer et = new ExpressionTokenizer(expr);
while (et.hasMoreTokens()) {
int token = et.nextToken();
if (token != ExpressionTokenizer.TOKEN_STRING)
currStringNode = null;
switch (token) {
case ExpressionTokenizer.TOKEN_STRING :
if (currStringNode == null) {
currStringNode = new StringNode(et.getTokenValue());
nodeStack.add(0, currStringNode);
} else {
// Add to the existing
currStringNode.value.append(" ");
currStringNode.value.append(et.getTokenValue());
}
break;
case ExpressionTokenizer.TOKEN_AND :
pushOpp(new AndNode());
break;
case ExpressionTokenizer.TOKEN_OR :
pushOpp(new OrNode());
break;
case ExpressionTokenizer.TOKEN_NOT :
pushOpp(new NotNode());
break;
case ExpressionTokenizer.TOKEN_EQ :
pushOpp(new EqualNode());
break;
case ExpressionTokenizer.TOKEN_NOT_EQ :
pushOpp(new NotNode());
// Sneak the regular node in. The NOT will
// be resolved when the next opp comes along.
oppStack.add(0, new EqualNode());
break;
case ExpressionTokenizer.TOKEN_RBRACE :
// Closeout the current group
resolveGroup();
break;
case ExpressionTokenizer.TOKEN_LBRACE :
// Push a group marker
pushOpp(null);
break;
case ExpressionTokenizer.TOKEN_GE :
pushOpp(new NotNode());
// Similar stategy to NOT_EQ above, except this
// is NOT less than
oppStack.add(0, new LessThanNode());
break;
case ExpressionTokenizer.TOKEN_LE :
pushOpp(new NotNode());
// Similar stategy to NOT_EQ above, except this
// is NOT greater than
oppStack.add(0, new GreaterThanNode());
break;
case ExpressionTokenizer.TOKEN_GT :
pushOpp(new GreaterThanNode());
break;
case ExpressionTokenizer.TOKEN_LT :
pushOpp(new LessThanNode());
break;
case ExpressionTokenizer.TOKEN_END :
break;
}
}
// Finish off the rest of the opps
resolveGroup();
if (nodeStack.size() == 0) {
throw new ParseException("No nodes created.", et.getIndex());
}
if (nodeStack.size() > 1) {
throw new ParseException("Extra nodes created.", et.getIndex());
}
if (oppStack.size() != 0) {
throw new ParseException("Unused opp nodes exist.", et.getIndex());
}
root = (Node)nodeStack.get(0);
| private void | pushOpp(org.apache.catalina.ssi.ExpressionParseTree$OppNode node)Pushes a new operator onto the opp stack, resolving existing opps as
needed.
// If node is null then it's just a group marker
if (node == null) {
oppStack.add(0, node);
return;
}
while (true) {
if (oppStack.size() == 0) break;
OppNode top = (OppNode)oppStack.get(0);
// If the top is a spacer then don't pop
// anything
if (top == null) break;
// If the top node has a lower precedence then
// let it stay
if (top.getPrecedence() < node.getPrecedence()) break;
// Remove the top node
oppStack.remove(0);
// Let it fill its branches
top.popValues(nodeStack);
// Stick it on the resolved node stack
nodeStack.add(0, top);
}
// Add the new node to the opp stack
oppStack.add(0, node);
| private void | resolveGroup()Resolves all pending opp nodes on the stack until the next group marker
is reached.
OppNode top = null;
while ((top = (OppNode)oppStack.remove(0)) != null) {
// Let it fill its branches
top.popValues(nodeStack);
// Stick it on the resolved node stack
nodeStack.add(0, top);
}
|
|