|
From: <cr...@us...> - 2009-08-20 15:32:02
|
Revision: 5657
http://jnode.svn.sourceforge.net/jnode/?rev=5657&view=rev
Author: crawley
Date: 2009-08-20 15:31:54 +0000 (Thu, 20 Aug 2009)
Log Message:
-----------
More work on the expression evaluator.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneArithmeticEvaluator.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneArithmeticEvaluatorTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneArithmeticEvaluator.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneArithmeticEvaluator.java 2009-08-20 11:24:38 UTC (rev 5656)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneArithmeticEvaluator.java 2009-08-20 15:31:54 UTC (rev 5657)
@@ -90,6 +90,15 @@
public long getValue() throws ShellSyntaxException {
return name != null ? evalName(name) : value;
}
+
+ @Override
+ public String toString() {
+ try {
+ return Long.toString(getValue());
+ } catch (ShellException ex) {
+ return "OOPS";
+ }
+ }
}
private final BjorneContext context;
@@ -112,6 +121,7 @@
}
private Primary evalExpression(CharIterator ci) throws ShellException {
+ int mark = opStack.size();
int ch = skipWhiteSpace(ci);
while ((ch = skipWhiteSpace(ci)) != -1 && ch != ')') {
int prefixOp = parseExpressionOperator(ci);
@@ -129,16 +139,17 @@
}
skipWhiteSpace(ci);
pushOperand(evalPrimary(ci));
+ if (prefixOp != NONE) {
+ pushOperator(prefixOp, mark);
+ }
skipWhiteSpace(ci);
int op = parseExpressionOperator(ci);
- if (prefixOp != NONE) {
- if (op == PLUSPLUS || op == MINUSMINUS) {
- pushOperator(op);
- skipWhiteSpace(ci);
- op = parseExpressionOperator(ci);
- }
- pushOperator(prefixOp);
+ if (op == PLUSPLUS || op == MINUSMINUS) {
+ pushOperator(op, mark);
+ skipWhiteSpace(ci);
+ op = parseExpressionOperator(ci);
}
+
ch = skipWhiteSpace(ci);
if (op == NONE) {
if (ch != -1 && ch != ')') {
@@ -150,19 +161,19 @@
} else if (ch == ')') {
throw new ShellSyntaxException("Expected a number or variable name in expression");
}
- pushOperator(op);
+ pushOperator(op, mark);
}
if (valStack.size() == 0) {
throw new ShellSyntaxException("No expression within \"$((...))\"");
}
- while (!opStack.isEmpty()) {
+ while (opStack.size() > mark) {
evalOperation();
}
- return valStack.getFirst();
+ return valStack.removeFirst();
}
- private void pushOperator(int op) throws ShellException {
- while (!opStack.isEmpty() && opStack.getFirst() <= op) {
+ private void pushOperator(int op, int mark) throws ShellException {
+ while (opStack.size() > mark && precedence.get(opStack.getFirst()) <= precedence.get(op)) {
evalOperation();
}
opStack.addFirst(op);
@@ -180,7 +191,6 @@
operand1 = valStack.removeFirst();
operand2 = null;
} else {
- System.err.println(op);
operand2 = valStack.removeFirst();
operand1 = valStack.removeFirst();
}
@@ -198,7 +208,7 @@
if (operand1.name == null) {
throw new ShellSyntaxException("Cannot apply ++ or -- to a number or a subexpression");
}
- value = evalName(operand1.name) + (op == PLUSPLUS ? 1 : -1);
+ value = evalName(operand1.name) + (op == PLUSPLUS + PREFIX ? 1 : -1);
context.setVariable(operand1.name, Long.toString(value));
res = new Primary(null, value);
break;
@@ -207,8 +217,8 @@
if (operand1.name == null) {
throw new ShellSyntaxException("Cannot apply ++ or -- to a number or a subexpression");
}
- value = evalName(operand1.name) + (op == PLUSPLUS ? 1 : -1);
- context.setVariable(operand1.name, Long.toString(value));
+ value = evalName(operand1.name);
+ context.setVariable(operand1.name, Long.toString(value + (op == PLUSPLUS ? 1 : -1)));
res = new Primary(null, value);
break;
case PLUS:
@@ -233,7 +243,7 @@
case PERCENT:
value = operand2.getValue();
if (value == 0) {
- throw new ShellException("Divide by zero in expression");
+ throw new ShellException("Remainder by zero in expression");
}
res = new Primary(null, operand1.getValue() % value);
break;
@@ -252,7 +262,8 @@
} else if (ch == '(') {
ci.nextCh();
Primary res = evalExpression(ci);
- if (ci.nextCh() != ')') {
+ skipWhiteSpace(ci);
+ if ((ch = ci.nextCh()) != ')') {
throw new ShellSyntaxException("Unmatched \"(\" (left parenthesis) in arithmetic expression");
}
return res;
@@ -304,7 +315,12 @@
return SLASH;
case '*':
ci.nextCh();
- return STAR;
+ if (ci.peekCh() == '*') {
+ ci.nextCh();
+ return STARSTAR;
+ } else {
+ return STAR;
+ }
case '%':
ci.nextCh();
return PERCENT;
@@ -315,9 +331,11 @@
private long parseNumber(CharIterator ci) {
StringBuilder sb = new StringBuilder();
- int ch;
- while (Character.isDigit((char) (ch = ci.nextCh()))) {
+ int ch = ci.peekCh();
+ while (ch != -1 && Character.isDigit((char) ch)) {
+ ci.nextCh();
sb.append((char) ch);
+ ch = ci.peekCh();
}
return Long.parseLong(sb.toString());
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-08-20 11:24:38 UTC (rev 5656)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-08-20 15:31:54 UTC (rev 5657)
@@ -951,8 +951,7 @@
return sb.toString();
}
-
- String variable(String parameter) throws ShellSyntaxException {
+ protected String variable(String parameter) throws ShellSyntaxException {
if (BjorneToken.isName(parameter)) {
VariableSlot var = variables.get(parameter);
return (var != null) ? var.getValue() : null;
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneArithmeticEvaluatorTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneArithmeticEvaluatorTest.java 2009-08-20 11:24:38 UTC (rev 5656)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneArithmeticEvaluatorTest.java 2009-08-20 15:31:54 UTC (rev 5657)
@@ -23,6 +23,7 @@
import junit.framework.TestCase;
import org.jnode.shell.ShellException;
+import org.jnode.shell.ShellSyntaxException;
import org.jnode.shell.bjorne.BjorneArithmeticEvaluator;
import org.jnode.shell.bjorne.BjorneContext;
import org.jnode.shell.io.CommandIOHolder;
@@ -44,13 +45,15 @@
super(null, null);
}
- /**
- * Expose method for testing
- */
@Override
protected void setVariable(String name, String value) {
super.setVariable(name, value);
}
+
+ @Override
+ protected String variable(String name) throws ShellSyntaxException {
+ return super.variable(name);
+ }
}
private static class TestBjorneArithmeticEvaluator extends BjorneArithmeticEvaluator {
@@ -97,4 +100,65 @@
assertEquals("0", ev.evaluateExpression(" - B"));
}
+ public void testInfixOperators() throws ShellException {
+ TestBjorneContext context = new TestBjorneContext();
+ context.setVariable("A", "1");
+ TestBjorneArithmeticEvaluator ev = new TestBjorneArithmeticEvaluator(context);
+ assertEquals("2", ev.evaluateExpression("1 + 1"));
+ assertEquals("2", ev.evaluateExpression("A + 1"));
+ assertEquals("0", ev.evaluateExpression("1 - 1"));
+ assertEquals("0", ev.evaluateExpression("1 - A"));
+ assertEquals("4", ev.evaluateExpression("2 * 2"));
+ assertEquals("2", ev.evaluateExpression("4 / 2"));
+ assertEquals("1", ev.evaluateExpression("4 % 3"));
+ assertEquals("27", ev.evaluateExpression("3 ** 3"));
+ try {
+ ev.evaluateExpression("4 / 0");
+ fail("no exception for '4 / 0'");
+ } catch (ShellException ex) {
+ // expected
+ }
+ try {
+ ev.evaluateExpression("4 % 0");
+ fail("no exception for '4 % 0'");
+ } catch (ShellException ex) {
+ // expected
+ }
+ }
+
+ public void testInfixPrecedence() throws ShellException {
+ TestBjorneContext context = new TestBjorneContext();
+ context.setVariable("A", "1");
+ TestBjorneArithmeticEvaluator ev = new TestBjorneArithmeticEvaluator(context);
+ assertEquals("0", ev.evaluateExpression("-1 * 2 + 2"));
+ assertEquals("4", ev.evaluateExpression("1 * 2 + 2"));
+ assertEquals("5", ev.evaluateExpression("1 + 2 * 2"));
+ assertEquals("9", ev.evaluateExpression("1 + 2 * 2 ** 2"));
+ assertEquals("8", ev.evaluateExpression("1 + 2 * 2 ** 2 + -A"));
+ }
+
+ public void testParentheses() throws ShellException {
+ TestBjorneContext context = new TestBjorneContext();
+ context.setVariable("A", "1");
+ TestBjorneArithmeticEvaluator ev = new TestBjorneArithmeticEvaluator(context);
+ assertEquals("-4", ev.evaluateExpression("-1 * (2 + 2)"));
+ assertEquals("4", ev.evaluateExpression("(1 * 2 + 2)"));
+ assertEquals("6", ev.evaluateExpression("((1) + 2) * 2"));
+ assertEquals("17", ev.evaluateExpression("1 + (2 * 2) ** 2"));
+ assertEquals("10", ev.evaluateExpression("1 + 2 * 2 ** 2 + -(-1)"));
+ }
+
+ public void testIncDec() throws ShellException {
+ TestBjorneContext context = new TestBjorneContext();
+ context.setVariable("A", "1");
+ TestBjorneArithmeticEvaluator ev = new TestBjorneArithmeticEvaluator(context);
+ assertEquals("1", ev.evaluateExpression("A++"));
+ assertEquals("2", context.variable("A"));
+ assertEquals("3", ev.evaluateExpression("++A"));
+ assertEquals("3", context.variable("A"));
+ assertEquals("3", ev.evaluateExpression("A--"));
+ assertEquals("2", context.variable("A"));
+ assertEquals("1", ev.evaluateExpression("--A"));
+ assertEquals("1", context.variable("A"));
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|