Menu

#13 Declare unkwon tokens as variables.

pending
nobody
None
FeatureRequest
None
2016-06-28
2016-06-26
No

Hi,

Suppose I let the user input a expression like sin(x), but x could be anything: variable12, z, randomName, u1, etc.

I want to get that unknown token (variable/constant) from the expression and use it as a key to retrieve a value in a map.

In other words, I want modify your code so, when parsing an expression for tokens, unkown tokens are automatically declared as StaticVariables.

I could not identify an appropriate place in the code to make such modification. Could you give me some ideias?

Discussion

  • Fathzer

    Fathzer - 2016-06-26

    Hi,
    Sorry if I didn't understand the question but it seems using StaticVariableSet is what you are looking for.
    http://javaluator.sourceforge.net/en/doc/tutorial.php?chapter=variables
    It does not require any code modification.
    Please let me know if I am wrong.
    Best regards,
    Jean-Marc Astesana

     
  • Pedro Vieira

    Pedro Vieira - 2016-06-27

    This is what I tried to do: Override the toValue method of DoubleEvaluator as to it search for the literal in a variables map before throwing the Illegal Argument Exception; then setting the variable if found.

    package userInteraction;
    
    import java.text.NumberFormat;
    import java.text.ParsePosition;
    import java.util.HashMap;
    import java.util.Locale;
    
    import com.fathzer.soft.javaluator.DoubleEvaluator;
    import com.fathzer.soft.javaluator.Parameters;
    import com.fathzer.soft.javaluator.StaticVariableSet;
    
    /**
     * An adapted Double evaluator from fathzer's javaluator package.
     * <p>
     * It searches for the literal in a variables map before throwing the 
     * Illegal Argument Exception in the toValue method. 
     */
    public class AdaptedEvaluator extends DoubleEvaluator {
    
        private static final ThreadLocal<NumberFormat> FORMATTER = new ThreadLocal<NumberFormat>() {
              @Override
              protected NumberFormat initialValue() {
                return NumberFormat.getNumberInstance(Locale.US);
              }
        };
    
        private static StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
    
        private static HashMap <String, Double> variableMap;
    
        public static void setMap(HashMap <String, Double> variableMap) {
            AdaptedEvaluator.variableMap = variableMap;
        }
    
        public AdaptedEvaluator() {
            super();        
        }
    
        public AdaptedEvaluator(Parameters parameters) {
            super(parameters);      
        }
    
        @Override
        protected Double toValue(String literal, Object evaluationContext) {
    
            ParsePosition p = new ParsePosition(0);
    
            Number result = FORMATTER.get().parse(literal, p);
    
            if (p.getIndex()==0 || p.getIndex()!=literal.length()) {
    
                if (variableMap.containsKey(literal)){
    
                    variables.set(literal, variableMap.get(literal));
                }           
                else {
                    throw new IllegalArgumentException( literal + 
                            " is not a number, nor a variable in the variable map");
                }
    
            }
    
            return result.doubleValue();
        }
    
    }
    
    package userInteraction;
    
    import java.util.HashMap;
    
    public class testing {
    
    
        public static void main(String[] args) {
    
            // Program logic that constructs the variable map.
            HashMap <String, Double> variableMap = new HashMap<String, Double>();
    
            variableMap.put("h1", 11.2);
    
            AdaptedEvaluator eval = new AdaptedEvaluator();
    
            AdaptedEvaluator.setMap(variableMap);
    
    
            // get user input and evaluate, without explicit declaration of the variable "h1".  
            String expression = "sin(h1)";
    
            double result = eval.evaluate(expression);
    
            System.out.print(result);
        }
    
    }
    

    When I try to run the testing it throws the exception:

    Exception in thread "main" java.lang.NullPointerException
    at userInteraction.AdaptedEvaluator.toValue(AdaptedEvaluator.java:63)
    at com.fathzer.soft.javaluator.DoubleEvaluator.toValue(DoubleEvaluator.java:48)
    at com.fathzer.soft.javaluator.AbstractEvaluator.output(AbstractEvaluator.java:133)
    at com.fathzer.soft.javaluator.AbstractEvaluator.evaluate(AbstractEvaluator.java:343)
    at com.fathzer.soft.javaluator.AbstractEvaluator.evaluate(AbstractEvaluator.java:214)
    at userInteraction.testing.main(testing.java:23)

    So result.doubleValue() is causing the excpetion but I cannot identify why.

    Is it clearer now what I am asking for?

    Regards,
    Pedro

     
  • Fathzer

    Fathzer - 2016-06-27

    Here is a version of your testing code that works without any subclass. It uses StaticVariableSet:
    package userInteraction;

    import com.fathzer.soft.javaluator.DoubleEvaluator;
    import com.fathzer.soft.javaluator.StaticVariableSet;

    public class Testing {
    
        public static void main(String[] args) {
            // Program logic that constructs the variable map.
    //        HashMap <String, Double> variableMap = new HashMap<String, Double>();
    //        variableMap.put("h1", 11.2);
    //        AdaptedEvaluator eval = new AdaptedEvaluator();
    //        AdaptedEvaluator.setMap(variableMap);
    
            DoubleEvaluator eval = new DoubleEvaluator();
            final StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
            variables.set("h1", 11.2);
    
            // get user input and evaluate, without explicit declaration of the variable "h1".  
            String expression = "sin(h1)";
    //        double result = eval.evaluate(expression);
            double result = eval.evaluate(expression, variables);
            System.out.print(result);
        }
    }
    

    Best regards,

    Jean-Marc Astesana

     

    Last edit: Fathzer 2016-06-27
  • Pedro Vieira

    Pedro Vieira - 2016-06-28

    Sir, you did not understand... (laughs)

    In my particular case, I cannot declare the varible in a default way. That is because it would require me to change too many parts in my program. If I can change only one single method, I save myself a lot of work and avoid some bugs.

    Anyway, below is what worked for me, in case anyone has a similar need.

    /**
     * An adapted Double evaluator from fathzer's javaluator package.
     * <p>
     * It searches for the literal in a variables map before throwing the 
     * Illegal Argument Exception in the toValue method.
     * <p>
     * This way, there is no need to explicitly declare the variable set.
     */
    public class AdaptedEvaluator extends DoubleEvaluator {
    
        private static final ThreadLocal<NumberFormat> FORMATTER = new ThreadLocal<NumberFormat>() {
              @Override
              protected NumberFormat initialValue() {
                return NumberFormat.getNumberInstance(Locale.US);
              }
        };
    
        private static StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
    
        private static HashMap <String, Double> variableMap;
    
        public static void setMap(HashMap <String, Double> variableMap) {
            AdaptedEvaluator.variableMap = variableMap;
        }
    
        public AdaptedEvaluator() {
            super();        
        }
    
        public AdaptedEvaluator(Parameters parameters) {
            super(parameters);      
        }
    
        @Override
        protected Double toValue(String literal, Object evaluationContext) {
    
            ParsePosition p = new ParsePosition(0);
    
            Number result = FORMATTER.get().parse(literal, p);
    
            if (p.getIndex()==0 || p.getIndex()!=literal.length()) {
    
                if (variableMap.containsKey(literal)){
                    // declare variable
                    variables.set(literal, variableMap.get(literal));
    
                    literal = variableMap.get(literal).toString();
    
                    result = FORMATTER.get().parse(literal, p);
                }           
                else {
                    throw new IllegalArgumentException( literal + 
                            " is not a number, nor a variable in the variable map");
                }
    
            }
    
            return result.doubleValue();
        }
    
    }
    

    Many thanks you for your attention,
    Pedro

     

Anonymous
Anonymous

Add attachments
Cancel