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.

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jnode-svn-commits mailing list
Jnode-svn-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits

Reply via email to