Wyjec applications developers tutorial

for Wyjec 1.0

The basics

Processing of Wyjec expression consists of two steps:

The Wyjec library provides Parser class that performs the first step inside its parse method. The method's signature is quite simple:
ExpressionTree parse(ReadableRawString input)
Actually, the parse method not only parses given expression but also performs semantic analysis on it. It means that all errors related to using non-existing functions or using values of invalid types will be reported by the parser.

The second step is performed by another class from the library - Evaluator. Its evaluate method accepts generated expression tree as a parameter and returns single value that contains the result of evaluation:
Value evaluate(ExpressionTree exprTree)

Both mentioned classes (Parser and Evaluator) make up a generic expression processing engine that may be used with any set of functions supported by an application. The evaluator doesn't need any explicit information about supported functions, because an expression tree generated by the parser contains direct references to functions used in parsed expression. The parser requires an array of functions that it should recognise and extra object that is responsible for parsing "constants" (more on these later).

Creating parser and evaluator objects

When creating some key objects from the Wyjec library one must specify a configuration object which is an instance of Config class. With the configuration object an application's developer may customise behaviour of Wyjec engine, mainly the way it uses system memory. While customising the configuration makes sense in some situations, in most cases you should just use the default one by calling Config.getDefaultConfig() method.

In most cases Wyjec functions are implemented by means of Java classes that inherit from Function. Each instance of such class represents single Wyjec function. While it is very simple and elegant approach, it doesn't fit some specific needs. From the user's point of view the Wyjec implementation offers virtually unlimited number of parameter-less functions which return values that are directly derived from names of the functions. For example, function named "1000" returns 1000, function named "567" returns 567 etc. To implement such functions effectively, the Wyjec uses constant parsers which are just instances of classes that implement IConstantsParser interface. Single constants parser effectively implements many Wyjec functions. The Wyjec library provides constants parser that recognises functions representing integer, float and date values, available as StandardConstantsParser.getInstance(). It's strongly recommended to use it directly and implement all domain specific functions using standard approach (Function subclasses).

Using the information presented above you may quickly create an instance of Wyjec parser:
Parser parser = new Parser(Config.getDefaultConfig(), StandardFunctions.getFunctions(), StandardConstantsParser.getInstance());
As you may guess, StandardFunctions.getFunctions() returns an array of all standard Wyjec functions provided by the library.

Creating an instance of Wyjec evaluator is even simpler:
Evaluator evaluator = new Evaluator(Config.getDefaultConfig());
It's strongly recommended to use the same configuration for the parser and the evaluator, so we use the default one in both cases.

Processing an expression

As I mentioned before, the first step of processing Wyjec expression is parsing its string form and generating an expression tree. When using the parser you must know that the parser doesn't accept standard String instances on the input. For efficiency reasons it uses RawString as a replacement. Fortunately, a conversion from String to RawString is very simple because the latter one offers a constructor that accepts a String instance.

Assuming that an expression is available in String variable named "expression", you may parse it using the following code:

ExpressionTree exprTree;
try {
    exprTree = parser.parse(new RawString(expression));
} catch (InvalidInputException e) {
    throw new RuntimeException("Error parsing expression", e);
}

With ExpressionTree instance in hand you may evaluate the expression with another method call:

Value result;
try {
    result = evaluator.evaluate(exprTree);
} catch (EvaluationException e) {
    throw new RuntimeException("Error evaluating expression", e);
}

The evaluator returns a Value instance which contains both value and type of the result. In real applications you should check the result's type before reading its value for further processing. Since Value class overrides toString method, for demonstration purposes you may simply write it to the output:

System.out.println("Result: " + result);

Complete example

After putting all pieces together you may write extremely simple Wyjec application that evaluates an expression given as an argument.

import pl.chyla.wyjec.Config;
import pl.chyla.wyjec.core.Value;
import pl.chyla.wyjec.evaluator.EvaluationException;
import pl.chyla.wyjec.evaluator.Evaluator;
import pl.chyla.wyjec.parser.ExpressionTree;
import pl.chyla.wyjec.parser.InvalidInputException;
import pl.chyla.wyjec.parser.Parser;
import pl.chyla.wyjec.stdconsts.StandardConstantsParser;
import pl.chyla.wyjec.stdfuncs.StandardFunctions;
import pl.chyla.wyjec.utils.RawString;


public class WyjecDemo {

    public static void main(String[] args) {
        // check and use command line argument
        if (args.length != 1) {
            System.out.println("Usage: WyjecDemo <expression>");
            System.exit(1);
        }
        String expression = args[0];
        // create parser and evaluator
        Parser parser = new Parser(Config.getDefaultConfig(), StandardFunctions.getFunctions(), StandardConstantsParser.getInstance());
        Evaluator evaluator = new Evaluator(Config.getDefaultConfig());
        // parse the expression...
        ExpressionTree exprTree;
        try {
            exprTree = parser.parse(new RawString(expression));
        } catch (InvalidInputException e) {
            throw new RuntimeException("Error parsing expression", e);
        }
        // ... evaluate it...
        Value result;
        try {
            result = evaluator.evaluate(exprTree);
        } catch (EvaluationException e) {
            throw new RuntimeException("Error evaluating expression", e);
        }
        // ... and print the result
        System.out.println("Result: " + result);
    }

}

Of course, in order to compile and execute the example you will need to use wyjec-1.0.jar. It's available on the Wyjec home page in download section.

Before actually using Wyjec in your application, read API documentation for all classes and methods used in the example. Take special care of the lifetime of objects returned by parser and evaluator. In some applications you may find CachingParser and SimpleParser useful (they're both wrappers around "raw" Wyjec parser).


© Copyright by Zbigniew Chyla 2005

Valid XHTML 1.0 Strict Viewable with Any Browser