Simple Grammar Parser

Sometimes there is a need to add scripting to your java application. The Parser for Simple Grammar can help you to evaluate simple expressions, like: AND, OR, +, -, *, /.

It supports three common data types: String, Number, Boolean. Moreover, it is possible to add custom functions and variables to your expressions.

The code for parser can be downloaded here: GitHub Repository

The common example is calculator, where we enter the expression, computer calculates it and returns the answer. We can start with simple expression:


IF(Auto=="Audi" OR Auto=="BMW", "German", "Unknown")

If we evaluate this expression, we can recieve two answers “German” or “Unknown” depending on the value in Variable Auto. In this expression we have the following elements:

Function: IF
with three parameters, which are separated by commas:
1. Auto==”Audi” OR Auto==”BMW”
2. “German”
3. “Unknown”

The first parameter is a complex expression of type Boolean, since we can get the TRUE or FALSE.

The second and the third parameters are String Literals.

The java application, which parses this expression can be written as follows:

//The list of functions
FunctionList functions = new FunctionList();
//The list of variables
VariableList variables = new VariableList();
//Our expression as String
String expr = "IF(Auto==\"Audi\" OR Auto==\"BMW\",
    \"German\", \"Unknown\")";
//We create new parser and as an input parameter we add expression
SimpleGrParser parser = new SimpleGrParser(new StringReader(expr));
//We parse expression
parser.parse();
//We get the root of the expression tree
Expression root = (Expression) parser.rootNode();
//We evaluate expression as String
String output = root.evaluateAsString(variables, functions);
//Output of the result
System.out.println(output);

Function List and Variable List contains our functions and variables. But what is the logic of our function (IF) and the value of our variable (Auto). We describe this directly in the new classes, which are shown below.

public class FunctionList implements FunctionHandler {
@Override
public String getValueAsString(String name, Expression[] params,
VariableValueHandler variables) throws Exception {
if (name.equals("IF")) {
if (params[0].evaluateAsBoolean(variables, this)) {
return params[1].evaluateAsString(variables, this);
} else {
return params[2].evaluateAsString(variables, this);
}
}
return null;
}
@Override
public Boolean getValueAsBoolean(String name, Expression[] params,
VariableValueHandler variables) throws Exception {
return null;
}
@Override
public Double getValueAsNumber(String name, Expression[] params,
VariableValueHandler variables) throws Exception {
return null;
}
@Override
public Class<?> getReturnType(String name) {
if (name.equals("IF")) {
return String.class;
}
return null;
}
}
public class VariableList implements VariableValueHandler {
@Override
public String getValueAsString(String name) {
if(name.equals("Auto")) {
return "Audi";
}
return null;
}
@Override
public Boolean getValueAsBoolean(String name) {
return null;
}
@Override
public Double getValueAsNumber(String name) {
return null;
}
@Override
public Class<?> getType(String name) {
if(name.equals("Auto")) {
return String.class;
}
return null;
}
}

The parser is written using JAVACC. This software helps to define own grammar, to parse it, and to construct the expression tree for further evaluation.

For our simple expression we describe the grammar and using JAVACC we build the following expression tree of java objects:


FuncExpr="IF"
BoolOrExpr="OR" (First Parameter in Function)
BoolEqualsExpr="=="
Variable="Auto"
StringLiteral="Audi"
BoolEqualsExpr="=="
Variable="Auto"
StringLiteral="BMW"
StringLiteral="German" (Second Parameter in Function)
StringLiteral="Unknown" (Third Parameter in Function)

On the next step we need to evaluate this tree. Every object contains functions:

evaluateAsString();
evaluateAsNumber();
evaluateAsBoolean();

By calling of this functions by every object recurcively, starting from IF we receive the result.