mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-06-27 08:29:31 +00:00
216 lines
6.0 KiB
Java
216 lines
6.0 KiB
Java
package com.bytezone.diskbrowser.visicalc;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
public class Expression implements Value
|
|
{
|
|
// Expressions:
|
|
// number
|
|
// cell address
|
|
// function
|
|
// expression [+-*/^] expression
|
|
// [+-=] expression
|
|
// ( expression )
|
|
// -expression
|
|
|
|
// From the reference card:
|
|
// Expressions are evaluated strictly from left to right except as modified by
|
|
// parentheses. You must start an expression with a +, a digit (0-9), or one of
|
|
// the symbols @-(. or #.
|
|
|
|
// @IF(D5=0,0,D9*(G5/(1-((1+G5)^-D4))
|
|
|
|
private final List<Value> values = new ArrayList<Value> ();
|
|
private final List<String> operators = new ArrayList<String> ();
|
|
|
|
public Expression (Sheet parent, String input)
|
|
{
|
|
String line = input.trim ();
|
|
|
|
System.out.printf ("New expression [%s]%n", input);
|
|
|
|
if (true)
|
|
{
|
|
int leftBracket = 0;
|
|
int rightBracket = 0;
|
|
for (char c : input.toCharArray ())
|
|
{
|
|
if (c == '(')
|
|
leftBracket++;
|
|
if (c == ')')
|
|
rightBracket++;
|
|
}
|
|
if (leftBracket != rightBracket)
|
|
{
|
|
System.out.printf ("Unbalanced brackets: left:%d, right:%d%n", leftBracket,
|
|
rightBracket);
|
|
line = "@ERROR()";
|
|
}
|
|
}
|
|
|
|
if (line.startsWith ("-"))
|
|
line = "0" + line;
|
|
else if (line.startsWith ("+"))
|
|
line = line.substring (1);
|
|
|
|
int ptr = 0;
|
|
while (ptr < line.length ())
|
|
{
|
|
char ch = line.charAt (ptr);
|
|
|
|
switch (ch)
|
|
{
|
|
case '@': // function
|
|
String functionText = getFunctionText (line.substring (ptr));
|
|
ptr += functionText.length ();
|
|
values.add (Function.getInstance (parent, functionText));
|
|
break;
|
|
|
|
case '(': // parentheses block
|
|
String bracketText = getFunctionText (line.substring (ptr));
|
|
ptr += bracketText.length ();
|
|
bracketText = bracketText.substring (1, bracketText.length () - 1);
|
|
values.add (new Expression (parent, bracketText));
|
|
break;
|
|
|
|
default:
|
|
if (ch == '.' || (ch >= '0' && ch <= '9')) // number
|
|
{
|
|
String numberText = getNumberText (line.substring (ptr));
|
|
ptr += numberText.length ();
|
|
values.add (new Number (Double.parseDouble (numberText)));
|
|
}
|
|
else if (ch >= 'A' && ch <= 'Z') // cell address
|
|
{
|
|
String addressText = getAddressText (line.substring (ptr));
|
|
ptr += addressText.length ();
|
|
values.add (parent.getCell (new Address (addressText)));
|
|
}
|
|
else
|
|
{
|
|
System.out.printf ("Unknown character [%s] in [%s]%n", ch, line);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ptr < line.length ())
|
|
{
|
|
ch = line.charAt (ptr);
|
|
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^')
|
|
operators.add (line.substring (ptr, ++ptr));
|
|
else
|
|
{
|
|
System.out.printf ("Unknown operator [%s] in [%s]%n", ch, line);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert values.size () > 0;
|
|
|
|
if (false)
|
|
{
|
|
ptr = 0;
|
|
for (Value val : values)
|
|
{
|
|
System.out.println (val.getValue ());
|
|
if (ptr < operators.size ())
|
|
System.out.println (operators.get (ptr++));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public double getValue ()
|
|
{
|
|
double value = values.get (0).getValue ();
|
|
for (int i = 1; i < values.size (); i++)
|
|
{
|
|
double nextValue = values.get (i).getValue ();
|
|
String operator = operators.get (i - 1);
|
|
if (operator.equals ("+"))
|
|
value += nextValue;
|
|
else if (operator.equals ("-"))
|
|
value -= nextValue;
|
|
else if (operator.equals ("*"))
|
|
value *= nextValue;
|
|
else if (operator.equals ("/"))
|
|
value /= nextValue;
|
|
else if (operator.equals ("^"))
|
|
value = Math.pow (value, nextValue);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private String getFunctionText (String text)
|
|
{
|
|
int ptr = text.indexOf ('('); // find first left parenthesis
|
|
int depth = 1;
|
|
while (++ptr < text.length ()) // find matching right parenthesis
|
|
{
|
|
if (text.charAt (ptr) == ')')
|
|
{
|
|
--depth;
|
|
if (depth == 0)
|
|
break;
|
|
}
|
|
else if (text.charAt (ptr) == '(')
|
|
++depth;
|
|
}
|
|
return text.substring (0, ptr + 1); // include closing parenthesis
|
|
}
|
|
|
|
private String getNumberText (String text)
|
|
{
|
|
int ptr = 0;
|
|
while (++ptr < text.length ())
|
|
{
|
|
char c = text.charAt (ptr);
|
|
if (c != '.' && (c < '0' || c > '9'))
|
|
break;
|
|
}
|
|
return text.substring (0, ptr);
|
|
}
|
|
|
|
private String getAddressText (String text)
|
|
{
|
|
int ptr = 0;
|
|
while (++ptr < text.length ())
|
|
{
|
|
char c = text.charAt (ptr);
|
|
if ((c < '0' || c > '9') && (c < 'A' || c > 'Z'))
|
|
break;
|
|
}
|
|
return text.substring (0, ptr);
|
|
}
|
|
|
|
@Override
|
|
public String toString ()
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
// text.append (String.format ("Has value ......... %s%n", hasValue));
|
|
// text.append (String.format ("Value ............. %f%n", value));
|
|
// text.append (String.format ("Function .......... %s%n", function));
|
|
// text.append (String.format ("Address ........... %s%n", address));
|
|
// text.append (String.format ("Operator .......... %s%n", operator));
|
|
// text.append (String.format ("Expression1 ....... %s%n", expression1));
|
|
// text.append (String.format ("Expression2 ....... %s%n", expression2));
|
|
int ptr = 0;
|
|
for (Value value : values)
|
|
{
|
|
text.append (value.getValue ());
|
|
if (ptr < operators.size ())
|
|
text.append (operators.get (ptr++));
|
|
}
|
|
|
|
return text.toString ();
|
|
}
|
|
|
|
public static void main (String[] args)
|
|
{
|
|
Expression ex = new Expression (null, "5+((4-(10-2)+6/3))*2");
|
|
System.out.println (ex.getValue ());
|
|
}
|
|
} |